简体   繁体   中英

C++ multithreading: keep only one thread (other than 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 stays 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;
        }
    }
}

--------------- The situation -------------------

I am writing an interactive ray tracing program. The world is first drawn by an OpenGL application, the user navigates through the world to choose a satisfying viewpoint and presses a key to start ray tracing. Before the ray tracing finishes, the user can change the viewpoint and presses the key to start a fresh new ray tracing. I use glfw to talk with operating system.

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();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM