Nelson P Nelson P - 26 days ago 12
C++ Question

Approach of using an std::atomic compared to std::condition_variable wrt pausing & resuming an std::thread in C++

This is a separate question but related to the previous question I asked here

I am using an

std::thread
in my
C++
code to constantly poll for some data & add it to a buffer. I use a
C++ lambda
to start the thread like this:

StartMyThread() {

thread_running = true;
the_thread = std::thread { [this] {
while(thread_running) {
GetData();
}
}};
}


thread_running
is an
atomic<bool>
declared in class header. Here is my
GetData
function:

GetData() {
//Some heavy logic
}


Next I also have a
StopMyThread
function where I set
thread_running
to false so that it exits out of the while loop in the
lambda block
.

StopMyThread() {
thread_running = false;
the_thread.join();
}


As I understand, I can pause & resume the thread using a
std::condition_variable
as pointed out here in my earlier question.

But is there a disadvantage if I just use the
std::atomic<bool>
thread_running
to execute or not execute the logic in
GetData()
like below ?


GetData() {
if (thread_running == false)
return;
//Some heavy logic
}


Will this burn more CPU cycles compared to the approach of using an
std::condition_variable
as described
here ?

Answer

There's two different problems being solved and it may depend on what you're actually doing. One problem is "I want my thread to run until I tell it to stop." The other seems to be a case of "I have a producer/consumer pair and want to be able to notify the consumer when data is ready." The thread_running and join method works well for the first of those. The second you may want to use a mutex and condition because you're doing more than just using the state to trigger work. Suppose you have a vector<Work>. You guard that with the mutex, so the condition becomes [&work] (){ return !work.empty(); } or something similar. When the wait returns, you hold the mutex so you can take things out of work and do them. When you're done, you go back to wait, releasing the mutex so the producer can add things to the queue.

You may want to combine these techniques. Have a "done processing" atomic that all of your threads periodically check to know when to exit so that you can join them. Use the condition to cover the case of data delivery between threads.