Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pthread_cond_wait doesn't unlock mutex

I can't find any evidence online of pthread_cond_wait being strange on Mac OS X, but it seems to be failing the simplest test for me.

The function

int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t * );

is supposed to unlock the mutex argument #2 and then wait for a signal to be sent on the condition argument #1. I wrote a simple program to test this, and also test for spurious wakeups:

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

pthread_t spin_thread;
pthread_mutex_t spin_mutex;
pthread_cond_t spin_cond;

int actual = 0;

void *condspin( void *v ) {
    int expected = 0;
    for ( ;; ) {
        if ( actual != expected ) printf( "unexpected %d\n", actual );
        else printf( "expected %d\n", actual );
        pthread_mutex_lock( &spin_mutex );
        printf( "locked\n" );
        expected = actual + 1;
        pthread_cond_wait( &spin_cond, &spin_mutex );
    }
    return NULL;
}

int main( int argc, char ** argv ) {
    pthread_mutex_init( &spin_mutex, NULL );
    pthread_cond_init( &spin_cond, NULL );
    pthread_create( &spin_thread, NULL, &condspin, NULL );

    for ( ;; ) {
        getchar();
        pthread_cond_signal( &spin_cond );
        printf( "signaled\n" );
        ++ actual;
    }
    return 0;
}

But it only acquires the lock once. The main thread doesn't even try to acquire the lock just to keep things simple.

Shadow:~ dkrauss$ cc condwait.c -o condwait
Shadow:~ dkrauss$ ./condwait 
expected 0
locked

signaled
expected 1

signaled

signaled

If I add a pthread_mutex_unlock after the pthread_cond_wait, it behaves as expected. (Or as well as you'd expect with only half a locking mechanism.) So, what gives?

like image 461
Potatoswatter Avatar asked Mar 01 '23 09:03

Potatoswatter


1 Answers

pthread_cond_wait re-acquires the mutex when it is awoken. The standard pattern for using pthreads mutexes is:

pthread_mutex_lock(&mutex);
// init work...
while (!some_condition)
    pthread_cond_wait(&cond, &mutex);
// finishing work...
pthread_mutex_unlock(&mutex);

This behavior is described in the SUS documentation for pthread_cond_wait as:

Upon successful return, the mutex has been locked and is owned by the calling thread. 
like image 141
bdonlan Avatar answered Mar 08 '23 10:03

bdonlan