1
votes

I am trying to find out execution of mutual exclusion and conditional variable in case of multiple threads produce and single thread consume.

Here is the sample code :

#include<stdio.h>
#include<pthread.h>
int done = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
void *thr2(void *arg) {
     pthread_t self;
     self=pthread_self();
     pthread_mutex_lock(&m);
     done = 1;
     pthread_cond_signal(&c);
     pthread_mutex_unlock(&m);
     return NULL;
}
void *thr1(void *arg) {
     pthread_t self;
     self=pthread_self();
     pthread_mutex_lock(&m);
     while (done == 0)
     {
          pthread_cond_wait(&c, &m);
     }
     pthread_mutex_unlock(&m);
}
int main(int argc, char *argv[]) {
     pthread_t p,q,r;
     pthread_create(&q, NULL, thr1, NULL);
     sleep(2);
     pthread_create(&p, NULL, thr2, NULL);
     pthread_create(&r, NULL, thr2, NULL);
     pthread_join(p,NULL);
     pthread_join(q,NULL);
     pthread_join(r,NULL);
     return 0;
}

In this code, I am expecting thread1 to wait on conditional variable done. So, thread2 or thread3 when any one starts and gets mutex and chanegs done to 1. It has to signal thread1 which is waiting and thread1 will start execution.

But, I see that even though thread1 is waiting on conditional variable done=0 and after signal from thread2, another thread which i created for thread2 method gets mutex.

I would like to know if anything wrong in my expectation of output. I am trying to implement blocking queue with similar case where there can be more than one producer and single consumer.

Thanks, Poovannan.

3

3 Answers

1
votes

Your expectation is wrong. Thread 1 will eventually wake up and get the mutex, since it's been signalled, but it's not guaranteed that Thread 3 won't get there first.

If you don't want your producer threads to "produce" when the queue is full (here, your queue is of length 1), then you need to have them wait as well - you can use a second condition variable for that:

int done = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c_done = PTHREAD_COND_INITIALIZER;
pthread_cond_t c_undone = PTHREAD_COND_INITIALIZER;

void *thr2(void *arg)
{
     pthread_mutex_lock(&m);
     /* wait for done to be zero */
     while (done != 0)
         pthread_cond_wait(&c_undone, &m);
     done = 1;
     pthread_cond_signal(&c_done);
     pthread_mutex_unlock(&m);
     return NULL;
}

void *thr1(void *arg)
{
     pthread_mutex_lock(&m);
     while (done == 0)
     {
          pthread_cond_wait(&c_done, &m);
     }
     done = 0;
     pthread_cond_signal(&c_undone);
     pthread_mutex_unlock(&m);
}
0
votes

From the official POSIX pthread_cond_signal reference:

The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond

and

If more than one thread is blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked

That means that you can't really tell which thread will be awoken by the signal. If you want to wake up just a specific thread, you have to use a condition variable specific for just that thread.

0
votes

Let's assume thr1 starts first. thr1 locks the mutex and waits on the condition and it releases the mutex m before going into wait. m is available for thread2 or thread3. One of thread2 or thread3 will lock the mutex and set done and signals thr1 and releases the mutex. But thr1 is not necessarily be able to reacquire the mutex m as another thread might have acquired the mutex.

Even though the condition thr1 waits on is true (done is set to 1 by thread2 or thread3), it won't return until it can lock the mutex again. Remember pthread_cond_wait() locks th mutex before returning. That means thr1 is still waiting.

Another point is thr1 should return NULL on completion or call pthread_exit(). Note that sleep is not a good synchronization mechanism.