2016-12-07 16 views
2

Рассмотрите эту базовую многопоточную программу, используя pthreads. У нас есть основной поток, создающий еще один поток, который выполняет некоторую работу.Статус Mutex после ложного пробуждения

bool done = false; 
mutex m; 
condition c; 

void foo() { 
    pthread_mutex_lock(&m); 
    //while(!done) { 
     pthread_cond_wait(&c, &m); 
     // Spuriously wakeup while child is doing work. 
     // child thread has NOT unlocked the mutex yet 
     // Do I now own the mutex? 
     // or am I waiting for child to unlock it? 
    //} 
    pthread_mutex_unlock(&m); 
} 

void * child(void *arg) { 
    pthread_mutex_lock(&m); 

    some_intense_work(); // this work is done while mutex is held! 
    // the main thread spuriously wakes up 
    // while this work is being done 
    // (while this child thread is holding the mutex) 

    done = true; 
    pthread_cond_broadcast(&c); 
    pthread_mutex_unlock(&m); 
} 

int main(int argc, char *argv[]) { 
    pthread_t p; 
    pthread_create(&p, NULL, child, NULL); 
    foo(); 
} 

Притворись, что мы реализуем выжидательную без окружающего While-п проверки для предиката, хотя мы понимаем, что никто не когда-либо должны делать это.

Теперь, если дочерний поток выполняет свою работу, в главном потоке возникает побочная пробуждение, каков будет статус мьютекса m? Будет ли основной поток владеть им без того, чтобы ребенок сначала отпирал его, чтобы оба его обладали?

Или же ложное пробуждение пропускает только ожидание состояния, но не ждет освобождения мьютекса?

+1

Когда ['pthread_cond_wait()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html) успешно возвращается, текущий поток блокирует мьютекс, независимо от того, является ли пробуждение ложным или нет. Бремя на пробужденный поток, чтобы проверить состояние, ожидание снова, если оно не выполнено. –

+0

, чтобы мы могли технически рассмотреть оба потока, чтобы иметь мьютекс в этот момент? – JMC

+0

Нет; только один поток блокирует мьютекс - вы не можете иметь оба потока с блокировкой мьютекса, потому что это не будет мьютексом. Трансляция не изменяет свойство взаимного исключения мьютекса. –

ответ

2

Звонок pthread_cond_wait() не может «ложно» просыпаться, в то время как в какой-то другой поток есть связанный мьютекс. Когда pthread_cond_wait() успешно возвращается, он будет требовать мьютекс, поэтому он не сможет успешно вернуться, пока мьютексы не будут доступны.

В вашем примере, поддельное бодрствование может произойти потому, что foo() может назвать pthread_cond_wait() и имеет паразитный след произойти до child() когда-либо получает возможность позвонить pthread_mutex_lock() в первую очередь.

Другая проблема в вашем примере (с прокомментированным кодом оставлена ​​отключена) заключается в том, что можно позвонить pthread_cond_wait() в never wake. Этот сценарий может произойти, если child() завершает всю свою обработку до того, как foo() сумеет получить мьютексы. в этом сценарии child() назовет pthread_cond_broadcast(), прежде чем главный поток ждет в pthread_cond_wait(), поэтому основной поток пропустит трансляцию. Поскольку foo() никогда не проверяет done, удерживая мьютексы, он не заметит, что child() закончил свою работу.

Именно поэтому pthread_cond_wait() почти всегда должен выполняться в цикле, который проверяет состояние.

+0

Спасибо. Незадолго до того, как вы ответили, я прокомментировал, что предположил, что это так, и вы точно это подтвердили. Цикл while остается необходимым. – JMC

+0

В вашем втором абзаце вы говорите, что может возникнуть ложный след, потому что 'foo()' вызывает 'pthread_cond_wait()' перед 'child()' может блокировать мьютекс. Как это могло случиться? Что может сигнализировать о состоянии до того, как ребенок заблокирует мьютекс, выполняет расчет, передает состояние и разблокирует мьютексы? AFAICS, 'foo()', безусловно, может называть 'pthread_cond_wait()', но он будет виден (и мьютексы разблокированы) до тех пор, пока ребенок не завершит свою обработку. –

+0

Сценарий «никогда не буди» - это настоящая проблема; если ребенок запускается первым, блокировка мьютекса в 'foo()' завершится неудачей, пока ребенок не разблокирует мьютекс после обработки, и поэтому передача действительно произойдет, а 'foo()' не находится в 'pthread_cond_wait()'. Что такое утвержденная/нормальная синхронизация вещей, так что 'foo()' получает зависание в 'pthread_cond_wait()' перед 'child()' захватывает мьютекс? –