0

Code:

void *inc_func(void *arg)
{
    pthread_mutex_lock(&mutex);
    pthread_cond_signal(&count_threshold_cv);
    sleep(1);
    pthread_mutex_unlock(&mutex);
}
void *watch(void *arg)
{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&count_threshold_cv,&mutex);
    sleep(1);
    pthread_mutex_unlock(&mutex);
}
int main()
{
    pthread_t id[2];
    pthread_create(&id[0],NULL,watch,NULL);
    pthread_create(&id[1],NULL,inc_func,NULL);
    int i;
    for(i=0;i<2;i++)
        pthread_join(id[i],NULL);
}

Now we have one mutex_unlock function to be executed in each thread. And one locked mutex. Why doesn't this lead to an undefined behaviour. Since both threads try to unlock the same mutex which leads to one trying to unlock an already unlocked mutex.

Edit: pthread_cond_wait releases the mutex for the second thread to use. Now consider the second thread executes pthread_cond_signal which leads to the first thread to reacquire the mutex. Now we have two threads having the same mutex lock,because both didn't get to execute the mutex_unlock because of the 'sleep' function. Is my understanding wrong?

Sreeraj Chundayil
  • 5,548
  • 3
  • 29
  • 68
  • This question is possible duplicate. Already answered in http://stackoverflow.com/questions/1778780/if-you-unlock-an-already-unlocked-mutex-is-the-behavior-undefined – Yasir Majeed Mar 28 '15 at 17:56
  • 1
    Showing some example code would definitly help to not misunderstand you. – alk Mar 28 '15 at 17:59

2 Answers2

1
  • pthread_mutex_lock() blocks if the mutex to be locked is already locked. It returns if the mutex got unlocked.

  • pthread_cond_wait() unlocks the mutex when starting to wait and locks is before returning. Returning might get delayed if the mutex in question is still locked. Returning then will be delay until the mutex got unlocked.

Putting the above together and applying it to the code you show one sees that each thread function nicely starts with a locking followed by an unlocking (and so on), so everything is fine.

Referring to the example code: pthread_cond_wait() returns when inc_func() had called pthread_mutex_unlock().


To successfully handle the scenario described by the example code you need to consider two special cases

  1. the case of signal coming first and
  2. the case of so called "spurious wake-ups", that is pthread_cond_wait() returning without having been signalled.

To handle both such case each condition should have a watch variable.

pthread_mutex_t mutex = ...
pthread_cond_t count_threshold_cv = ...

int signalled = 0;

void *inc_func(void *arg)   
{
  pthread_mutex_lock(&mutex);

  pthread_cond_signal(&count_threshold_cv);
  signalled = 1;

  pthread_mutex_unlock(&mutex);  
}

void *watch(void *arg)
{
  pthread_mutex_lock(&mutex);

  while (0 == signalled)
  {
    pthread_cond_wait(&count_threshold_cv,&mutex);
  }

  pthread_mutex_unlock(&mutex);
}

int main(void)
{
  pthread_t id[2];
  pthread_create(&id[0],NULL,watch,NULL);
  pthread_create(&id[1],NULL,inc_func,NULL);
  int i;
  for(i=0;i<2;i++)
    pthread_join(id[i],NULL);
}  
alk
  • 69,737
  • 10
  • 105
  • 255
  • I rephrased the question better I think – Sreeraj Chundayil Mar 28 '15 at 18:18
  • @InQusitive: You wrongly assume that `pthread_cond_wait()` returns due to `pthread_cond_signal()` having been called. This is not the case. – alk Mar 28 '15 at 18:22
  • There cannot be two threads holding the same mutex per definition. Thats what they are for. `pthread_mutex_lock()` will simply block if called on an already locked mutex, would not return. @InQusitive – alk Mar 28 '15 at 18:28
  • @InQusitive: Did your real code initilaise the mutex it uses? Does your real code check the outcome of each `pthread_*()` function called, tests whether it perhaps failed? – alk Mar 28 '15 at 18:29
  • Yes, Anyway my understanding was wrong about the mutex_cond_wait. Now it is clear. :) Please put your second comment in the answer. – Sreeraj Chundayil Mar 28 '15 at 18:30
1

If indeed the order is

  • watch runs first and locks (while inc_func waits)
  • watch which has the mutex waits using pthread_cond_wait which unlocks the mutext and blocks as per the documentation

These functions atomically release mutex and cause the calling thread to block on the condition variable cond;

This allows the following

  • inc_func acquires the mutex then signals (at this point the mutex is yet to be released)
  • inc_func releases the mutex
  • Because the mutex was released and the mutex unlocked the execution of watch resumes having locked the mutex as per the documentation:

Upon successful return, the mutex has been locked and is owned by the calling thread.

  • What follows is a legal release of the mutex.

The scenario that you did not consider is what if the code of inc_func executes first without switching to watch

  • inc_func locks the mutex
  • inc_func signals but there's no one to be signaled, which is OK.
  • inc_func unlocks the mutex
  • watch locks the mutex
  • then waits for the conditional variable but there will be no one to signal it so it'll wait forever.
Scis
  • 2,934
  • 3
  • 23
  • 37