2
votes

When using a condition variable, http://en.cppreference.com/w/cpp/thread/condition_variable describes the typical steps for the thread that notifies as:

  1. acquire a std::mutex (typically via std::lock_guard)
  2. perform the modification while the lock is held
  3. execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification)

For the simple case shown below, is it necessary for the main thread to lock "stop" when it modifies it? While I understand that locking when modifying shared data is almost always a good idea, I'm not sure why it would be necessary in this case.

std::condition_variable cv;
std::mutex mutex;
bool stop = false;

void worker() {
    std::unique_lock<std::mutex> lock(mutex);
    cv.wait(lock, [] { return stop; })
}

// No lock (Why would this not work?)
void main() {
     std::thread(worker);
     std::this_thread::sleep_for(1s);
     stop = true;
     cv.notify_one();
}

// With lock: why is this neccesary?
void main() {
     std::thread mythread(worker);
     std::this_thread::sleep_for(1s);
     {
         std::unique_lock<std::mutex>(mutex);
         stop = true;
     }
     cv.notify_one();
     mythread.join();
}
2
Your code terminates because you're destroying a unjoined thread. Please run some basic tests on your code before posting.Kerrek SB
Sorry about that- added a join.mmnormyle
I assume you are aware of following sentence in the docs and you are asking why this may be? "Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread."moooeeeep

2 Answers

6
votes

For the simple case shown below, is it necessary for the main thread to lock "stop" when it modifies it?

Yes, to prevent race condition. Aside from issues of accessing shared data from different threads, which could be fixed by std::atomic, imagine this order of events:

worker_thread: checks value of `stop` it is false
main_thread: sets `stop` to true and sends signal
worker_thread: sleeps on condition variable

In this situation worker thread would possibly sleep forever and it would miss event of stop set to true simply because wakeup signal was already sent and it missed it.

Acquiring mutex on modification of shared data is required because only then you can treat checking condition and going to sleep or acting on it in worker thread as atomic operation as whole.

1
votes

Is , it is necessary.
First of all, from the standard point of view, you code exhibits undefined behavior, as stop is not atomic and isn't change under a lock, while other threads may read or write to it.
both reading and writing must occur under a lock if multiple threads read and write to a shared memory.

From hardware perspective, if stop isn't changed under a lock, other threads, even through they lock some lock, aren't guaranteed to "see" the change that was done. locks don't just prevent from other threads to intervene, they also force the latest change to be read or written into the main memory, and hence all the threads can work with the latest values.