pthread_cond_wait не разблокирует мьютекс

Я не могу найти в Интернете никаких доказательств того, что pthread_cond_wait странно работает в Mac OS X, но, похоже, он не прошел простейший тест для меня.

Функция

int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t * );

предполагается разблокировать аргумент мьютекса № 2, а затем дождаться отправки сигнала в аргументе условия № 1. Я написал простую программу, чтобы проверить это, а также проверить наличие ложных пробуждений:

#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;
}

Но он получает блокировку только один раз. Основной поток даже не пытается получить блокировку просто для простоты.

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

signaled
expected 1

signaled

signaled

Если я добавлю pthread_mutex_unlock после pthread_cond_wait, он будет вести себя так, как ожидалось. (Или так же хорошо, как и следовало ожидать, только с половиной запирающего механизма.) Итак, что дает?


person Potatoswatter    schedule 23.08.2009    source источник


Ответы (1)


pthread_cond_wait повторно захватывает мьютекс, когда он пробуждается. Стандартный шаблон для использования мьютексов pthreads:

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

Это поведение описано в документации SUS для pthread_cond_wait следующим образом:

Upon successful return, the mutex has been locked and is owned by the calling thread. 
person bdonlan    schedule 23.08.2009
comment
Ага! Имеет смысл! Теперь, почему ни один из документов, которые я читал (а я читал несколько), не говорит об этом??? - person Potatoswatter; 24.08.2009
comment
это задокументировано в спецификации SUS (цитата добавлена), а также на справочной странице linuxthreads для pthread_cond_wait. Я не знаю о mac os x, но это тоже должно документироваться... - person bdonlan; 24.08.2009
comment
OS X почти не имеет документации. Он говорит это и только это: функция pthread_cond_wait() атомарно разблокирует аргумент мьютекса и ожидает аргумента cond. Я действительно прочитал предоставленную вами ссылку, но меня смутило использование пассивного залога. Мьютекс был заблокирован — это сбивающий с толку способ сказать, что функция блокирует мьютекс, особенно в интерфейсе, где на пользователя ложится множество требований. - person Potatoswatter; 24.08.2009