- Jaki jest najlepszy sposób kontrolowania, do którego wątku dostarczany jest sygnał?
Jak wskazał @ zoli2k, jawne wyznaczenie pojedynczego wątku do obsługi wszystkich sygnałów, które chcesz obsłużyć (lub zestawu wątków, z których każdy ma określone obowiązki), jest dobrą techniką.
- Jaki jest najlepszy sposób, aby poinformować inny wątek (który może być faktycznie zajęty), że sygnał dotarł? [...]
- Jak mogę bezpiecznie obsługiwać przekazywanie informacji o pojawieniu się sygnału do innych wątków? Czy to musi się zdarzyć w programie obsługi sygnału?
Nie powiem „najlepiej”, ale oto moja rekomendacja:
Zablokuj wszystkie żądane sygnały main
, tak aby wszystkie wątki dziedziczyły tę maskę sygnału. Następnie utwórz specjalny wątek odbierający sygnał jako pętlę zdarzeń sterowaną sygnałem, wysyłając nowo przybyłe sygnały jako inną komunikację wewnątrz wątku .
Najłatwiej to zrobić, aby wątek akceptował sygnały w pętli za pomocą sigwaitinfo
lubsigtimedwait
. Wątek następnie w jakiś sposób konwertuje sygnały, być może rozgłasza pthread_cond_t
, budzi inne wątki z większą liczbą operacji we / wy, kolejkuje polecenie w kolejce bezpiecznej dla wątków specyficznej dla aplikacji, cokolwiek.
Alternatywnie, specjalny wątek mógłby pozwolić na dostarczanie sygnałów do obsługi sygnału, zdejmując maskę przed dostarczeniem tylko wtedy, gdy jest gotowy do obsługi sygnałów. (Dostawa sygnału przez teleskopowe są bardziej podatne na błędy niż akceptacji sygnału poprzez sigwait
rodzinę, jednak). W tym przypadku obsługi sygnału wykonuje odbiornika niektóre proste i działanie sygnału bezpieczny asynchroniczny: ustawienie sig_atomic_t
flagi, wzywając sigaddset(&signals_i_have_seen_recently, latest_sig)
, write
() bajt do nieblokującego potoku własnego itp. Następnie, z powrotem w swojej zamaskowanej pętli głównej, wątek przekazuje odbiór sygnału do innych wątków, jak powyżej.
( AKTUALIZACJA @caf słusznie wskazuje, że sigwait
podejścia są lepsze).
sigwaitinfo()
(lubsigtimedwait()
), a następnie wysyła je do reszty aplikacji, jak opisano w ostatnim akapicie.Zgodnie ze standardem POSIX wszystkie wątki powinny mieć ten sam PID w systemie i za pomocą
pthread_sigmask()
można zdefiniować maskę blokowania sygnału dla każdego wątku.Ponieważ dozwolone jest zdefiniowanie tylko jednego programu obsługi sygnału na PID, wolę obsługiwać wszystkie sygnały w jednym wątku i wysyłać,
pthread_cancel()
jeśli działający wątek wymaga anulowania. Jest to preferowana metoda,pthread_kill()
ponieważ umożliwia definiowanie funkcji czyszczenia dla wątków.W niektórych starszych systemach, z powodu braku odpowiedniej obsługi jądra, działające wątki mogą mieć inny PID niż PID wątku macierzystego. Zobacz często zadawane pytania dotyczące obsługi sygnałów w linuxThreads w systemie Linux 2.4 .
źródło
make menuconfig
ze świeżo sklonowaną gałęzią git master uClibc. Nie jest to wybór pomiędzy starymi LinuxThreads i nowszej NPTL jako implementacji wątku POSIX, ale pomoc od roku 2012 nadal odradza wyborze NPTL. Dlatego we współczesnych wbudowanych systemach Linux nadal często można zobaczyć przestarzałą implementację LinuxThreads, nawet jeśli system ma wystarczająco nowsze jądro Linuksa.Gdzie jestem do tej pory:
Mam jeszcze do sortowania
signal
vssigaction
,pselect
,sigwait
,sigaltstack
, i cała masa innych bitów i kawałków POSIX (i nie-POSIX) API.źródło
Sygnały IMHO, Unix V i wątki posix nie mieszają się dobrze. Unix V to 1970. POSIX to 1980;)
Istnieją punkty anulowania i jeśli zezwolisz na sygnały i pthreads w jednej aplikacji, w końcu skończysz pisanie pętli wokół każdego połączenia, które może zaskakująco zwrócić EINTR.
Więc to, co zrobiłem w (nielicznych) przypadkach, w których musiałem programować wielowątkowość w systemie Linux lub QNX, polegało na zamaskowaniu wszystkich sygnałów dla wszystkich (z wyjątkiem jednego) wątków.
Kiedy nadejdzie sygnał Unix V, proces przełącza stos (to było tyle współbieżności w Unix V, ile można było uzyskać w procesie).
Jak wskazują inne posty, teraz może być możliwe poinformowanie Systemu, który wątek posix będzie ofiarą tego przełączania stosu.
Kiedyś udało ci się uruchomić wątek obsługujący sygnał, pozostaje pytanie, jak przekształcić informacje o sygnale w coś cywilizowanego, którego mogą użyć inne wątki. Wymagana jest infrastruktura do komunikacji między wątkami. Jednym z użytecznych wzorców jest wzorzec aktora, w którym każdy z twoich wątków jest celem dla jakiegoś mechanizmu przesyłania wiadomości w procesie.
Tak więc, zamiast anulować inne wątki lub zabijać je (lub inne dziwne rzeczy), powinieneś spróbować skierować Signal z kontekstu Signal do wątku obsługującego Signal, a następnie użyć mechanizmów komunikacji wzorców aktorów, aby wysłać semantycznie użyteczne wiadomości do tych aktorów, którzy potrzebują informacji związanych z sygnałem.
źródło