shapeare shapeare - 1 month ago 13
C++ Question

C++ multithreading: keep only one thread (other thatn the main thread) alive at a time

I have a function that does some heavy tasks, so I would like to run it in a thread other than the main thread. The code looks like:

Data global_data;
void heavy_task() {
...//update global_data
}

void main() {
while (True) {
if (user_press_w) {
std::thread t(heavy_task);
t.detach();
}
}
}


How can I modify the code so that only one thread is running at a time? For example, if the user presses w which starts a thread and then before the first thread with heavy_task finishes, she presses w again, the first thread will stop and the second one starts to run. This would also be helpful in the situation when the user keeps pressing the key, in which case only the thread triggered by the last time key detection stay alive.

----------------- Solution -------------------

I have revised my code as suggested by Adrian Colomitchi,

std::shared_ptr<std::thread> my_thread;
bool should_terminate = false;

Data global_data;
void heavy_task() {
// This function actually does its work in a loop
// so I check should_terminate at each iteration
while (...) {
...
if (should_terminate) return;
}
}

void main() {
while (True) {
if (user_press_w) {
should_terminate = true;
if (my_thread!= nullptr && my_thread->joinable())
my_thread->join();
my_thread= std::make_shared<thread>(heavy_task);
should_terminate = false;
}
}
}

Answer

You need to make the heavy_task interruptible: while doing the things, periodically check a flag which should tell it if it is to continue or drop everything and exit prematurely.

With this in place, when you receive another command for a heavy task, you raise first the "interrupt" flag, join the worker thread to make sure it "died" (so, no thread.detach() before) and then launch the new heavy_task.

Something on the lines of:

Data global_data;

void heavy_task(bool& shouldStop) {
    while(! ready && ! shouldStop) {
      // update **some** global data, in as small slices as you can afford
    }
}

void main() {
    bool interruptWThread=false;

    std::shared_ptr<std::thread> thread;

    while (True) {
        if (user_press_w) {
            if(thread) {
              interruptWThread=true;
              thread->join(); // wait here until thread exit is confirmed
              interruptWThread=false;
            }
            thread = std::make_shared<std::thread>(
              [& interruptWThread]->heavy_task(interruptWThread)
            );
            // nope!! Never detach a thread you may still need later
            // t.detach();
        }
    }
}