3

I am reading about condition variables in Effective Modern C++ by Scott Meyers book below is text.

std::condition_variable   cv
std::mutex                m

T1 (detecting task)

...
cv.notify_one();


T2 (reacting task)

...
{
  std::unique_lock<std::mutex> lk(m);
  cv.wait(lk);

  ...
}

Here author mentions as below

Mutexs are used to control access to shared data, but it's entirely possible that the detecting and reacting tasks have no need for such mediation. For example, the detecting task might be responsible for initializing a global data structure, then turning it over to reacting task for use. If the detecting task never access the data structure after initialzing it, and if the reacting task never access it before the detecting task indicates that it's ready, the two tasks will stay out of each other's way through program logic. There will be no need for mutex.

On above text I have difficulty in understanding

  1. What does author mean by " two tasks will stay out of each other's way through program logic" ?

  2. What does author mean by no need for mutex?

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
venkysmarty
  • 11,099
  • 25
  • 101
  • 184

4 Answers4

2

Mutex are used to solve race conditions, e.g.:

A race condition occurs when two or more threads can access shared data and they try to change it at the same time

In your case that doesn't happen since the operations done on your structure will be done in a different time frame, i.e.: not causing any race conditions. Since you don't have two threads writing at the same time you don't need a mutex.

Also consider that most problems arise when you have "check-then-act" (e.g. "check" if the value is X, then "act" to do something that depends on the value being X) and another thread does something to the value in between the "check" and the "act".

DevSolar
  • 67,862
  • 21
  • 134
  • 209
dynamic
  • 46,985
  • 55
  • 154
  • 231
  • Thanks for answering. But my questions are different from what you answered – venkysmarty Dec 03 '15 at 11:55
  • I answered your questions: they stay out of each other means that they will never change the data in the same time hence no need for mutex – dynamic Dec 03 '15 at 11:56
2

The detecting task and the reacting task both access the same data, but it is guaranteed by program logic that they never access that data at the same time. Therefore, they do not need a mutex (or any other mechanism) to prevent concurrent access to the data, because such concurrent access is prevented by other means. The other means are the program logic.

"Program logic" refers to the control flow of the program. I'll reformat the code slightly:

Data shared_data;

std::condition_variable cv;
std::mutex m;

void detecting_task()
{
  initialise(shared_data);
  cv.notify_one();
}

void reacting_task()
{
  {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk);
  }
  process(shared_data);
}

Even if both detecting_task and reacting_task start at the same time, you can see that they cannot possibly act on shared_data concurrently. The program logic is such that detecting_task only touches the data before cv is notified, and reacting_task only touches the data after cv is notified. So they cannot possibly overlap, and hence don't need to protect shared_data by a mutex.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 2
    Unless the reacting thread's wait wakes spuriously, in which case bad things happen. – Casey Dec 03 '15 at 14:34
  • Maybe this is an entirely different problem but the documentation of [std::condition_variable](http://en.cppreference.com/w/cpp/thread/condition_variable) states that "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". This sounds to me as if an additional mutex is required in any case. No matter if the access is serialized or atomic - something which confuses me a lot. – Hauke Heibel Dec 03 '15 at 15:09
  • @HaukeHeibel That's talking about the `std::mutex` which is protecting `cv` itself, and you can see that it is indeed there in the code. The point is that you don't need a mutex to protect `shared_data`. I've edited the code to clarify the scope of the mutex. – Angew is no longer proud of SO Dec 03 '15 at 15:14
  • 1
    I see. Only, if I used the implementation of [wait](http://en.cppreference.com/w/cpp/thread/condition_variable/wait) with a predicate in order to guard against spurious wakeups I would need to guard the predicate's boolean modification in the detection_task() and only that. – Hauke Heibel Dec 03 '15 at 15:25
1

Essentially the text says: when two threads do not access any shared resources, there is no need for synchronizing access to the resources. That is, if each thread just uses its own data structures and no other thread accesses them, there is no need for any locking via a mutex - no other thread is going to access the respective resource.

Given the context, it seems a simple message passing system, i.e., the thing using the mutex and the condition variable, is described which does all the necessary synchronization: the "detecting thread" notices something and sends a notification via the message passing system to the "reacting thread". The only thing shared between them is the message passing object.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

I don't fully understand the citation either. If you are not protecting shared data, mutex is not necessary for memory access, for sure. This may mean, that detecting task will not require to lock the mutex.

But, the c++11 the condition_variable requires a mutex for working. And this is because, at least some underlying OS implementations are requiring a mutex, such as pthreads

See : Why do pthreads’ condition variable functions require a mutex?

Community
  • 1
  • 1
galinette
  • 8,896
  • 2
  • 36
  • 87