Reputation: 385
I am experiencing some problems with thread synchronization using pthread conditional variable. I have one thread that parses messages extracting some values and another thread that increments some variables using the extracted values. I used pthread conditional variable to synchronize these two threads. The first thread looks like the snippet below:
if(parse_ok){
pthread_mutex_lock(&q_mutex);
q = extract_value();
q_changed = true;
printf("...awake\n");
pthread_cond_signal(&q_cond_var);
pthread_mutex_unlock(&q_mutex);
}
The worker thread looks like the snippet below:
while(true){
pthread_mutex_lock(&q_mutex);
if( !q_changed ){
std::cout<<"waiting..!"<<std::endl;
pthread_cond_wait(&q_cond_var, &q_mutex);
}
if(q_changed){
q_changed = false;
_actual_q += q;
_total_q += q;
_quant_q += q/_fixed_quantity;
}
pthread_mutex_unlock(&q_mutex);
}//END of while TRUE
This code works correctly most of time. Sometimes happens, when I receive a lot of messages, one after the other, that the sleeping thread skips some awakening. May I need some semaphore to block receiving thread until the working thread completes its work? How? Thanks in advance.
Upvotes: 1
Views: 239
Reputation: 7832
The way your code is written, there's no guarantee that the second worker thread will process the new input every time the first thread signals it. You can extend the use the q_changed
variable, however, to ensure that this happens.
Change your first thread to this:
if(parse_ok){
pthread_mutex_lock(&q_mutex);
while (q_changed) // Always wait in in loop
pthread_cond_wait(&q_cond_var, &q_mutex);
q = extract_value();
q_changed = true;
pthread_cond_signal(&q_cond_var);
pthread_mutex_unlock(&q_mutex);
}
And change your second, worker thread to this:
while(true){
pthread_mutex_lock(&q_mutex);
while( !q_changed ) // Always wait in a loop
pthread_cond_wait(&q_cond_var, &q_mutex);
q_changed = false;
_actual_q += q;
_total_q += q;
_quant_q += q/_fixed_quantity;
pthread_cond_signal(&q_cond_var);
pthread_mutex_unlock(&q_mutex);
}
Upvotes: 1
Reputation: 1725
There are several things potentially biting you here:
a) printf and cout are not threadsafe, thus their output might not reflect the actual order of the waiting and waking in the code.
b) spurious wakeups aren't handled efficiently in your code. I'd change the if( !q_changed )
conditional to while (!q_changed)
to minimize the amount of time you take to re-wait on the condition variable if spuriously awoken (this will also allow you to remove the last if (q_changed)
conditional block).
EDIT (based on comments by @EOF et al): If using a modern C++/C implementation (I assume you're not since you're using pthreads), then it is most likely that b) is your problem. The race in this case is that waiting thread can wake then unlock the mutex. In the meantime the signaling thread acquires the lock and signals. Since you weren't waiting on the condition, you didn't get the signal. Note however, that it's not a problem - you still process the data - it's just that you didn't output a 'waiting' message to cout in this case.
Upvotes: 2