How to make sure pthread_cond_wait() doesn't miss any pthread_cond_signal()?

Viewed 195

I have a Read thread and multiple write threads as the following.

Read thread:

pthread_mutex_lock(mutex);
while(1){
   pthread_cond_wait(cond, mutex);
   switch(state){
   //do something
   }
}
pthread_mutex_unlock(mutex);

Write thread1:

pthread_mutex_lock(mutex);
state = work;
pthread_cond_signal(cond);
//do something
pthread_mutex_unlock(mutex);

Write thread2:

pthread_mutex_lock(mutex);
state = lunch;
pthread_cond_signal(cond);
//do something
pthread_mutex_unlock(mutex);

Assume state is the shared variable and Read thread goes into waiting before all the write threads.

Say the two write threads try to get mutex at the same time and write1 acquires mutex and sends cond. At this point of time both write2 and read threads are locked on the mutex, and so far to my understanding, no thread has a priority to the mutex so we can't be sure when write1 releases the mutex that read thread will acquire it, which will lead to a missed signal and an overwritten state.

I have two questions here:

  1. Is my understanding correct, that the above situation is possible?
  2. If so, how do I make sure that no signal is missed in my code ?
2 Answers
  1. Is my understanding correct, that the above situation is possible?

Yes, you are correct.

  1. If so, how do I make sure that no signal is missed in my code.

If you want to make sure that every change of the variable state is noticed by the "read thread", then you must make sure that no "write thread" changes the variable state until it has been acknowledged by the "read thread". For example, you could make the "read thread" read the value of state and then set that variable to a special value, to indicate to the "writer threads" that state may now be overwritten with a new value.

However, this means that not only does the "read thread" have to wait for the "writer threads", but the "writer threads" must also wait for the "read thread". This is the producer-consumer problem. A typical solution would be to have two condition variables instead of one:

  • One for the "writer threads" to indicate to the "reader thread" that new data is ready to be read.
  • One for the "reader thread" to indicate to the "writer threads" that new data can now be written.

In order to minimize threads waiting for each other, you may want to allow for more than one set of data to be stored in your program at once, for example by implementing a queue.

As you don't want to miss any state change, the write threads should not overwrite the variable but write the states into a FIFO (that you can implement as a linked list or a pipe or a circular buffer with read/write pointers for examples). Then, the write threads will push the states (one new element per-state in the FIFO) and the read thread will pop them one by one until the FIFO is empty (as it may have multiple states in the FIFO upon each wake up).

So, you can keep the current signaling implementation but just change the way state is managed: a FIFO of states instead of a single variable.

Related