2013-06-03 13 views
11

Napisałem program wielowątkowy z pthread, używając modelu producent-konsument.Pthread Mutex: pthread_mutex_unlock() zużywa dużo czasu

Kiedy używam profilera Intel VTune do profilowania mojego programu, okazało się, że producent i konsument spędzają dużo czasu na pthread_mutex_unlock. Nie rozumiem, dlaczego tak się stało. Myślę, że wątki mogą długo czekać, zanim będą mogły nabyć muteks, ale zwolnienie muteksu powinno być szybkie, prawda?

Poniższa migawka pochodzi z Intel VTune. Pokazuje kody, w których konsument próbuje pobrać element z bufora i czas zużyty przez każdą linię kodu.

Moje pytanie brzmi, dlaczego pthread_mutex_unlock ma taki narzut? Czy problem dotyczy samego Pthread mutex lub sposobu, w jaki go używam? enter image description here

+0

Odblokowanie muteksa może być powolne, jeśli istnieje wiele niezgodności na temat tego muteksu, ponieważ część prac nad odblokowaniem budzi wszystkie wątki oczekujące na muteksie. – caf

+6

Myślę, że byłoby interesujące zobaczyć wyniki, jeśli przeniesiesz wywołanie 'pthread_mutex_unlock()' powyżej wywołania 'pthread_cond_signal()'. Nie ma wymogu trzymania muteksu podczas sygnalizowania zmiennej warunku (tylko podczas oczekiwania na nią) i podejrzewam, że to, co powoduje, że sygnał powoduje rywalizację na muteksie, ponieważ wątek, który zostaje zwolniony, natychmiast próbuje uzyskać muteks, który wątek sygnalizacji wciąż trzyma. –

+2

@MichaelBurr Dobry punkt! Testuję z twoją sugestią, a program jest teraz o 40% szybszy. –

Odpowiedz

2

Funkcja pthread_mutex_unlock() powinna zwolnić obiekt mutex, do którego odwołuje się mutex. Ale sposób, w jaki muteks jest uwalniany, zależy od atrybutu type mutex. Jeśli istnieją wątki zablokowane na obiekcie mutex, do którego odwołuje się mutex, gdy wywoływana jest funkcja pthread_mutex_unlock(), co powoduje, że muteks staje się dostępny, polityka planowania określa, który wątek ma nabyć muteks.

Jeśli typem muteks jest PTHREAD_MUTEX_NORMAL, nie można podać zakleszczenia. Próba ponownego zablokowania muteksa powoduje zakleszczenie. Jeśli wątek próbuje odblokować muteks, który nie został zablokowany lub odblokowany muteks, powstaje niezdefiniowane zachowanie.

Jeśli typem muteks jest PTHREAD_MUTEX_ERRORCHECK, należy podać informację o błędzie. Jeśli wątek próbuje ponownie zablokować muteks, który już został zablokowany, zostanie zwrócony błąd. Jeśli wątek próbuje odblokować muteks, który nie został zablokowany lub odblokowany muteks, zostanie zwrócony błąd.

Jeśli typem muteksu jest PTHREAD_MUTEX_RECURSIVE, to muteks powinien zachować koncepcję liczby blokad. Gdy wątek pomyślnie uzyska muteks po raz pierwszy, liczba blokad zostanie ustawiona na jeden. Za każdym razem, gdy wątek odwoła się do tego muteksu, liczba blokad zostanie zwiększona o jeden. Za każdym razem, gdy wątek odblokuje muteks, liczba blokad zostanie zmniejszona o jeden. Kiedy liczba blokad osiągnie zero, muteks będzie dostępny dla innych wątków do pozyskania. Jeśli wątek próbuje odblokować muteks, który nie został zablokowany lub odblokowany muteks, zostanie zwrócony błąd.

Jeśli typem muteksu jest PTHREAD_MUTEX_DEFAULT, próba rekursywnego zablokowania muteksu powoduje niezdefiniowane zachowanie. Próba odblokowania muteksa, jeśli nie została zablokowana przez wywołujący wątek, powoduje niezdefiniowane zachowanie. Próba odblokowania muteksu, jeśli nie jest zablokowana, powoduje niezdefiniowane zachowanie.

Zwykle wolę używać muteksów PTHREAD_MUTEX_RECURSIVE, ponieważ w tym przypadku muteks stanie się dostępny, gdy licznik osiągnie zero, a wątek wywołujący nie ma już żadnych blokad na tym muteksie.

Powiązane problemy