Reputation: 5859
I just started learning pthread condition variable. But below code is not working as expected.
#include<iostream>
#include<pthread.h>
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_threshold_cv = PTHREAD_COND_INITIALIZER;
int count=0;
void *inc_func(void *arg)
{
pthread_mutex_lock(&mutex);
int c;
while(1)
{
cin>>c;
if(c==8){
pthread_cond_signal(&count_threshold_cv);break;}
}
cout<<"inc count reached 8"<<endl;
pthread_mutex_unlock(&mutex);
}
void *watch(void *arg)
{
pthread_mutex_lock(&mutex);
while(1){
pthread_cond_wait(&count_threshold_cv,&mutex);
break;
}
cout<<"This executed"<<endl;
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t id[26];
pthread_create(&id[0],NULL,inc_func,NULL);
pthread_create(&id[1],NULL,watch,NULL);
int i;
for(i=0;i<2;i++)
{
pthread_join(id[i],NULL);
}
}
when the input is 8 this code gets hanged at "inc count reached 8? I am not able to understand. Where is my understanding wrong?
Upvotes: 1
Views: 322
Reputation: 239011
The correct solution to this is to make the watch
thread only wait if the condition it is waiting for has not occured yet.
The condition appears to be c == 8
(since that is what is signalled), so you will need to make the c
variable global so that it is shared between the threads, then change the watch
thread to do:
void *watch(void *arg)
{
pthread_mutex_lock(&mutex);
while (c != 8) {
pthread_cond_wait(&count_threshold_cv, &mutex);
}
cout<<"This executed"<<endl;
pthread_mutex_unlock(&mutex);
return 0;
}
Now it doesn't matter which thread runs first: your code is correct either way. This is the right way to use conditional variables: in general, the waiter should do:
pthread_mutex_lock(&mutex);
while (!condition)
pthread_cond_wait(&cond, &mutex);
/* ... */
and the signaller should do:
pthread_mutex_lock(&mutex);
/* ... something that potentially makes condition true ... */
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
Upvotes: 3
Reputation: 6866
The important thing here is that pthread_cond_signal
will unblock at least one of the threads that are blocked on that condition variable (meaning which are currently blocked on a call to pthread_cond_wait
on that same condition variable). If at the moment when one thread calls pthread_cond_signal
there is no other thread waiting on that condition then basically nothing happens.
Keeping this in mind, the flow of your program is something like this:
inc_func()
, which locks the mutex before anything else;inc_func()
keeps waiting for the number 8 to be entered, keeping the mutex locked all this time;inc_func
managed to lock the mutex, the second thread is created;8
and the condition gets signaled from thread 1; thread 2 is not waiting on this condition yet, so it remains blocked trying to lock the mutex;pthread_cond_wait
.At this point, thread 1 has already finished, thread 2 is blocked waiting for the condition to be signaled, and the main thread is waiting for it to finish. There is nobody else to signal that condition, so you have a hang.
For a quick fix that will probably work most of the times, you could try changing the order in which you start the threads(start the watch
thread first). But keep in mind and understand why I used bold for probably and most of the times.
The correct way to fix this would be to rethink your locking strategy: lock the mutexes in the smallest scope possible and keep them locked for the shortest time possible.
Upvotes: 2
Reputation: 3271
Swap the thread's execution sequence:
pthread_create(&id[1],NULL,watch,NULL);
pthread_create(&id[0],NULL,inc_func,NULL);
If you run thread0
as first, thread1
never gets past mutex lock, so it doesn't start waiting. Than thread0
ends, and only then thread1
executes pthread_cond_wait()
, but there's no thread to do signal
.
If you start thread1
first, it gets to the waiting part.
Upvotes: 1