Search code examples
cmultithreadingpthreadsmutexrace-condition

When calling pthread_cond_signal on program with 4 threads, the same thread gets the mutex


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_t node[4];
pthread_mutex_t token;
pthread_cond_t cond;
int id=0;

void *func(int n)
   {
        int count = 0;
        while (count < 10){
                 pthread_mutex_lock(&token);
                while (id != n){
                        printf("Whoops not my turn, id=%d\n",n);
                        pthread_cond_wait(&cond, &token);}
                //if (id == n){
                        count += 1;
                        printf ("My turn! id= %d\n",n);
                        printf("count %d\n", count);
                        if (id == 3){
                                id = 0;}
                        else{
                                id += 1;}
                        //}else{
                        //      printf("Not my turn! id=%d\n",n);}
                        //      pthread_mutex_unlock(&token);
                        //      sleep(2);}
                        pthread_mutex_unlock(&token);
                        pthread_cond_signal(&cond);}
                        printf ("ID=%d has finished\n",n);

        return(NULL);
   }

int main()
   {
   int i;
   pthread_mutex_init(&token,NULL);
        pthread_cond_init(&cond,NULL);
   for(i=0;i<4;i++)
      pthread_create(&node[i],NULL,(void *)func,(void *)i);

   for(i=0;i<4;i++)
      pthread_join(node[i],NULL);

   pthread_mutex_destroy(&token);

   return 0;
   }

This is my code, it is a C program using threads. I don't think it's purpose needs to be known here, but I will give an example of the problem I have.

Say thread with id 1 (defined by n in func) gets the mutex, and returns "My turn! id=1". When mutex_unlock and cond_signal are called, the next thread to get the mutex will actually be thread with id 1 again, and it will print "Whoops not my turn, id=1". And only then will thread with id 2 get the mutex, and print "My turn! id=2", but when thread with id = 2 will get the mutex after that. Here is my program output:

Whoops not my turn, id=1
Whoops not my turn, id=2
Whoops not my turn, id=3
My turn! id= 0
count 1
Whoops not my turn, id=0
My turn! id= 1
count 1
Whoops not my turn, id=1
My turn! id= 2
count 1
Whoops not my turn, id=2
My turn! id= 3
count 1
Whoops not my turn, id=3
My turn! id= 0
count 2
Whoops not my turn, id=0
My turn! id= 1
count 2
Whoops not my turn, id=1
My turn! id= 2
count 2
Whoops not my turn, id=2
My turn! id= 3
count 2
Whoops not my turn, id=3
My turn! id= 0
count 3
Whoops not my turn, id=0
My turn! id= 1
count 3
Whoops not my turn, id=1
My turn! id= 2
count 3
Whoops not my turn, id=2
My turn! id= 3
count 3
Whoops not my turn, id=3
My turn! id= 0
count 4
Whoops not my turn, id=0
My turn! id= 1
count 4
Whoops not my turn, id=1
My turn! id= 2
count 4
Whoops not my turn, id=2
My turn! id= 3
count 4
Whoops not my turn, id=3
My turn! id= 0
count 5
Whoops not my turn, id=0
My turn! id= 1
count 5
Whoops not my turn, id=1
My turn! id= 2
count 5
Whoops not my turn, id=2
My turn! id= 3
count 5
Whoops not my turn, id=3
My turn! id= 0
count 6
Whoops not my turn, id=0
My turn! id= 1
count 6
Whoops not my turn, id=1
My turn! id= 2
count 6
Whoops not my turn, id=2
My turn! id= 3
count 6
Whoops not my turn, id=3
My turn! id= 0
count 7
Whoops not my turn, id=0
My turn! id= 1
count 7
Whoops not my turn, id=1
My turn! id= 2
count 7
Whoops not my turn, id=2
My turn! id= 3
count 7
Whoops not my turn, id=3
My turn! id= 0
count 8
Whoops not my turn, id=0
My turn! id= 1
count 8
Whoops not my turn, id=1
My turn! id= 2
count 8
Whoops not my turn, id=2
My turn! id= 3
count 8
Whoops not my turn, id=3
My turn! id= 0
count 9
Whoops not my turn, id=0
My turn! id= 1
count 9
Whoops not my turn, id=1
My turn! id= 2
count 9
Whoops not my turn, id=2
My turn! id= 3
count 9
Whoops not my turn, id=3
My turn! id= 0
count 10
ID=0 has finished
My turn! id= 1
count 10
ID=1 has finished
My turn! id= 2
count 10
ID=2 has finished
My turn! id= 3
count 10
ID=3 has finished

As you can see, after each success, and the thread prints "My turn!", it will get the mutex after that and cause an "Whoops not my turn!". I don't understand why this happens as I call pthread_cond_signal, which should signal another thread to wake up before the current thread can reobtain the mutex. Please help me find this solution as I think there is something important I am missing. If my explanation is lacking, please feel free to ask me for more information. Thank you very much for your time!


Solution

  • @rcgldr already gave a very good explanation on the timing involved. If you want to increase your odds of giving another thread a chance, try adding a call to pthread_yield, which should give the scheduler the opportunity to pick a different thread, though that won't be a guarantee, either.