Oprócz problemu „zbyt wielu sygnałów” sygnały można wyraźnie zignorować. Od man 2 signal
:
If the signal signum is delivered to the process, then one of the
following happens:
* If the disposition is set to SIG_IGN, then the signal is ignored.
Sygnały można również blokować. Od man 7 signal
;
A signal may be blocked, which means that it will not be delivered
until it is later unblocked. Between the time when it is generated
and when it is delivered a signal is said to be pending.
Zarówno zablokowane, jak i zignorowane zestawy sygnałów są dziedziczone przez procesy potomne, więc może się zdarzyć, że proces nadrzędny aplikacji zignoruje lub zablokuje jeden z tych sygnałów.
Co się stanie, gdy dostarczonych zostanie wiele sygnałów, zanim proces zakończy obsługę poprzednich? To zależy od systemu operacyjnego. signal(2)
Podręcznika powiązany powyżej Omawia:
- System V zresetuje ustawienie sygnału do wartości domyślnej. Co gorsza, szybkie dostarczanie wielu sygnałów spowodowałoby wywołania rekurencyjne (?).
- BSD automatycznie blokuje sygnał do momentu zakończenia procedury obsługi.
- W Linuksie zależy to od ustawionych flag kompilacji GNU
libc
, ale oczekiwałbym zachowania BSD.
signal(2)
podręcznika Linuksa dla sugeruje zdecydowanie, aby uniknąć tego zamieszania, używającsigaction(2)
zamiast tego.Nie możesz ufać, że każdy wysłany sygnał zostanie dostarczony. Na przykład jądro Linuksa „łączy” SIGCHLD, jeśli proces zajmuje dużo czasu w obsłudze SIGCHLD z zakończonego procesu potomnego.
Aby odpowiedzieć na inną część twojego pytania, sygnały zostają „umieszczone w kolejce” wewnątrz jądra, jeśli liczba różnych sygnałów dotrze w zbyt krótkim odstępie czasu.
Należy użyć
sigaction()
, aby ustawić obsługi sygnału zsa_sigaction
członkasiginfo_t
, ustawieniesa_mask
członeksiginfo_t
starannie argument. Myślę, że oznacza to maskowanie przynajmniej wszystkich sygnałów „asynch”. Według strony podręcznika użytkownika dla Linuksasigaction()
ukryjesz również przetwarzany sygnał. Myślę, że powinieneś ustawićsa_flags
członka na SA_SIGINFO, ale nie pamiętam, dlaczego mam takie przesądy. Wierzę, że dzięki temu twój proces będzie obsługiwał sygnał, który pozostanie ustawiony bez warunków wyścigu i taki, który nie zostanie przerwany przez większość innych sygnałów.Napisz swoją funkcję obsługi sygnału bardzo, bardzo ostrożnie. Zasadniczo wystarczy ustawić zmienną globalną, aby wskazać, że sygnał został złapany, a reszta procesu zajmie się żądaną akcją dla tego sygnału. W ten sposób sygnały będą maskowane przez jak najmniej czasu.
Ponadto bardzo dokładnie przetestujesz kod obsługi sygnału. Przeprowadź go w małym procesie testowym i wyślij jak najwięcej sygnałów SIGUSR1 i SIGUSR2, na przykład z 2 lub 3 programów do wysyłania sygnałów specjalnego przeznaczenia. Miksuj także inne sygnały, gdy masz pewność, że Twój kod może szybko i poprawnie obsługiwać SIGUSR1 i SIGUSR2. Przygotuj się na trudne debugowanie.
Jeśli używasz Linuksa i tylko Linuksa, możesz pomyśleć o
signalfd()
utworzeniu deskryptora pliku, który możeszselect()
lub odpytać, aby odebrać te sygnały. Użyciesignalfd()
może ułatwić debugowanie.źródło
Gwarantuje się, że sygnał zostanie dostarczony w tym sensie, że jeśli proces zostanie pomyślnie wywołany
kill
, wtedy cel otrzyma sygnał. Jest to asynchroniczne: nadawca nie może wiedzieć, kiedy sygnał zostanie odebrany lub przetworzony. Nie gwarantuje to jednak, że sygnał zostanie dostarczony. Cel może umrzeć, zanim będzie mógł przetworzyć sygnał. Jeśli cel ignoruje sygnał w momencie jego dostarczenia, sygnał nie będzie miał wpływu. Jeśli cel odbierze wiele wystąpień tego samego numeru sygnału, zanim będzie mógł je przetworzyć, sygnały mogą (i zazwyczaj są) scalone: jeśli wyślesz ten sam sygnał dwukrotnie do procesu, nie będziesz wiedział, czy proces odbierze sygnał raz lub dwa razy. Sygnały są w większości zaprojektowane do zabicia procesu lub jako sposób na zwrócenie uwagi na proces, nie są przeznaczone do komunikacji jako takiej.Jeśli potrzebujesz niezawodnej dostawy, potrzebujesz innego mechanizmu komunikacji. Istnieją dwa główne mechanizmy komunikacji między procesami: potok umożliwia komunikację jednokierunkową; gniazdo umożliwia dwukierunkową komunikację i wiele połączeń do tego samego serwera. Jeśli potrzebujesz, aby cel przetwarzał tyle powiadomień, ile je wysyłasz, wysyłaj bajty za pomocą potoku.
źródło
Jądro może łączyć standardowe sygnały, jeśli więcej niż jeden jest dostarczany, gdy jest zablokowany. Z drugiej strony sygnały w czasie rzeczywistym nie są podobnie upośledzone.
Ze strony podręcznika użytkownika signal (7) :
Spróbuj użyć sygnału z liczbą w zakresie od SIGRTMIN do SIGRTMAX.
źródło
ulimit -i
pokazuje tę wartość jako 63432 na Ubuntu 18.04.