views:

252

answers:

1

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?

+4  A: 

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.
bdonlan
Aha! Makes perfect sense! Now why don't any of the docs I read (and I read a few) say so???
Potatoswatter
it is documented in the SUS spec (citation added), and also in the linuxthreads manpage for pthread_cond_wait. I don't know about mac os x, but it should document this as well...
bdonlan
OS X has almost no documentation. It says this and only this: "The pthread_cond_wait() function atomically unlocks the mutex argument and waits on the cond argument." I did actually read the reference you provided but I was confused by its use of the passive voice. "The mutex has been locked" is a confusing way of saying "the function locks the mutex," especially in an interface where many requirements fall upon the user.
Potatoswatter