Jeśli nie zablokujesz muteksu w ścieżce kodowej, która zmienia stan i sygnały, możesz utracić wybudzenia. Rozważ tę parę procesów:
Proces A:
pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
Proces B (nieprawidłowy):
condition = TRUE;
pthread_cond_signal(&cond);
Następnie rozważ możliwość przeplotu instrukcji, gdzie condition
zaczyna się jako FALSE
:
Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
condition
Jest teraz TRUE
, ale jest zablokowany Proces A czeka na zmiennej warunkowej - to brakowało sygnał wzbudzenia. Jeśli zmienimy Proces B, aby zablokować muteks:
Proces B (poprawny):
pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
... wtedy powyższe nie może wystąpić; przebudzenie nigdy nie zostanie pominięte.
(Zauważ, że możesz faktycznie przenieść to pthread_cond_signal()
samo po znaku pthread_mutex_unlock()
, ale może to spowodować mniej optymalne planowanie wątków i koniecznie zablokowałeś muteks już w tej ścieżce kodu z powodu zmiany samego warunku).
pthread_signal_cond()
można przesunąć po odblokowaniu mutexa, chociaż prawdopodobnie lepiej tego nie robić. Być może bardziej poprawne jest stwierdzenie, że w momencie, w którym dzwoniszpthread_signal_cond()
, będziesz musiał już zablokować muteks, aby zmodyfikować sam warunek.pthread_cond_timedwait()
lubpthread_cond_wait()
, tworzone jest dynamiczne wiązanie między tym muteksem a zmienną warunku, które pozostaje w co najmniej jeden wątek jest zablokowany w zmiennej warunku. W tym czasie efekt próby oczekiwania przez dowolny wątek na tę zmienną warunku przy użyciu innego muteksu jest niezdefiniowany. ”Zgodnie z tą instrukcją:
Znaczenie instrukcji przewidywalnego zachowania harmonogramu zostało wyjaśnione przez Dave'a Butenhof (autor książki Programming with POSIX Threads ) na comp.programming.threads i jest dostępne tutaj .
źródło
caf, w przykładowym kodzie Proces B modyfikuje
condition
bez blokowania mechanizmu mutex. Jeśli Proces B po prostu zablokował muteks podczas tej modyfikacji, a następnie nadal odblokował muteks przed wywołaniempthread_cond_signal
, nie byłoby problemu - czy mam rację?Intuicyjnie wierzę, że stanowisko kawiarni jest poprawne: dzwonienie
pthread_cond_signal
bez posiadania blokady mutex to zły pomysł. Ale przykład kawiarni nie jest w rzeczywistości dowodem na poparcie tego stanowiska; jest to po prostu dowód na poparcie znacznie słabszego (praktycznie oczywistego) stanowiska, że złym pomysłem jest modyfikowanie wspólnego stanu chronionego muteksem, chyba że najpierw zablokujesz ten muteks.Czy ktoś może podać przykładowy kod, w którym wywołanie,
pthread_cond_signal
po którym następuje,pthread_mutex_unlock
daje poprawne zachowanie, ale wywołanie,pthread_mutex_unlock
po którym następuje,pthread_cond_signal
daje nieprawidłowe zachowanie?źródło
pthread_cond_signal
afterpthread_mutex_unlock
może spowodować utratę wybudzenia, ponieważ sygnał jest przechwytywany w „złym” wątku, takim, który został zablokowany po zobaczeniu zmiany w predykacie. Jest to problem tylko wtedy, gdy ta sama zmienna warunku może być używana dla więcej niż jednego predykatu i nie używaszpthread_cond_broadcast
, co i tak jest rzadkim i delikatnym wzorcem.