2013-02-20 11 views
9

Mam 2 procesy (A, B) dzielące ten sam muteks (za pomocą wywołań WaitForSingleObject/ReleaseMutex). Wszystko działa dobrze, ale kiedy proces A ulega awarii, proces B mruczy radośnie. Po ponownym uruchomieniu procesu A występuje impas.Wywołany przez Win32 muteks nie został zwolniony, gdy proces się zawiesza

Głębsze dochodzenie ujawnia, że ​​proces B może pomyślnie wywołać funkcję ReleaseMutex() dwukrotnie po zakończeniu procesu A.

Moja interpretacja: Po zakończeniu procesu A, muteks jest nadal zablokowany, ale własność muteksa łatwo przechodzi do procesu B (który jest błędem). Właśnie dlatego nuci się radośnie, wywołując WaitForSingleObject (otrzymując w zamian WAIT_OBJECT_0) i ReleaseMutex (otrzymując w zamian TRUE).

Czy możliwe jest użycie prymitywu synchronizacji o nazwie podobnej do Mutex w taki sposób, że awaria w procesie A spowoduje zwolnienie muteksa?

Jednym z rozwiązań jest użycie SEH i złapanie awarii oraz zwolnienie muteksa, ale mam nadzieję, że system Windows ma solidne prymitywy, które nie powodują takich zakleszczeń podczas awarii procesu.

+2

To może być interesujący artykuł do przeczytania: http://blogs.msdn.com/b/oldnewthing/archive/2005/09/12/463977.aspx –

Odpowiedz

24

Niektóre podstawowe założenia trzeba zrobić tutaj o tym, jak mutex działa w systemie Windows:

  • mutex jest system operacyjny, który jest przedmiotem odniesienia zliczane. To nie zniknie, dopóki ostatni uchwyt na mutex jest zamknięty
  • dowolny uchwyt Pozostaje unclosed gdy proces kończy się zamknięty przez system operacyjny, zmniejszanie licznika odwołań
  • mutex jest re-uczestnik, nazywając WaitForSingleObject na muteksie na tym samym wątku kończy się sukcesem i musi być zrównoważony równą liczbą wywołań ReleaseMutex
  • posiadany muteks staje się porzucony, gdy wątek, który jest właścicielem, kończy się bez wywoływania ReleaseMutex. Wywoływanie obiektu WaitForSingleObject na muteksie w tym stanie generuje WAIT_ABANDONED kod powrotu błędu
  • nigdy nie jest błędem w systemie operacyjnym.

Możesz wyciągnąć z tego wnioski z tego, co zaobserwowałeś. Nic nie dzieje się z muteksem, gdy A się zawiesza, B nadal ma na nim rączkę. Jedyny możliwy sposób, w jaki B może zauważyć, że A się rozbił, gdy A się rozbił, gdy był właścicielem muteksu. Bardzo niskie szanse na to i łatwe do zaobserwowania, ponieważ B zablokuje się. Bardziej prawdopodobne jest to, że B będzie szczęśliwe, ponieważ jest całkowicie pozbawione przeszkód, nikt już nie będzie mógł nabyć muteksu.

Ponadto, zakleszczenie, gdy A zaczyna się od tyłu, udowadnia coś, co już wiedziałeś: B posiada muteks permanentnie z jakiegoś powodu. Być może dlatego, że rekurencyjnie pozyskała muteksa. Wiesz o tym, ponieważ zauważyłeś, że musisz dwukrotnie wywołać funkcję ReleaseMutex. To jest błąd, który musisz naprawić.

Musisz zabezpieczyć się przed awaryjnym procesem rodzeństwa i musisz napisać dla niego wyraźny kod.Zadzwoń do OpenProcess na rodzeństwo, aby uzyskać uchwyt obiektu procesu. Wywołanie WaitForSingleObject na uchwycie zakończy się, gdy proces się zakończy.

+4

+1 dla "To nigdy nie jest błąd w systemie operacyjnym." : p – Deanna

+0

Przepraszam, że nie oznaczyłem tego jako odpowiedzi, ale .. lepiej późno niż nigdy. Dzięki, nie znałem znaczenia opuszczonego państwa. –

9

Jeśli proces zawieszający muteksa powoduje jego zawieszenie, staje się on porzucony. Od drugiej aplikacji zależy, w jaki sposób zajmuje się tym stanem, zwrócony z funkcji oczekiwania.

Jeśli otrzyma WAIT_ABANDONED, to może dalej działać tak, jakby wszystko było ok (prawdopodobnie to, co teraz robi) lub "potencjalnie niestabilne dane, postępuj ostrożnie". Własność nie jest automatycznie przekazywana do innego procesu.

+10

Domyślam się, że Proces B otrzymuje 'WAIT_ABANDONED' i uważa, że ​​oznacza 'WAIT_FAILED' (zamiast" powiodło się w nieoczekiwany sposób "), więc próbuje uzyskać mutex po raz drugi. –

Powiązane problemy