Używaj, sigaction()
chyba że masz bardzo ważne powody, aby tego nie robić.
signal()
Interfejs ma antyku (i stąd dostępności) na swoją korzyść, a jest zdefiniowany w normie C. Niemniej jednak ma wiele niepożądanych cech, których sigaction()
unika - chyba że używasz flag wyraźnie dodanych, sigaction()
aby umożliwić wierne symulowanie starego signal()
zachowania.
signal()
Funkcja nie (muszą) blokują inne sygnały z przybyciem gdy prąd obsługowy wykonania; sigaction()
może blokować inne sygnały do czasu powrotu aktualnej procedury obsługi.
signal()
Funkcja (zazwyczaj) resetuje plecy sygnał do działania SIG_DFL
(domyślnie) dla prawie wszystkich sygnałów. Oznacza to, że program signal()
obsługi musi przeinstalować się w pierwszej akcji. Otwiera to również okno podatności między momentem wykrycia sygnału a ponownym zainstalowaniem programu obsługi, podczas którego, jeśli nadejdzie druga instancja sygnału, zachodzi domyślne zachowanie (zwykle przerywane, czasem z uprzedzeniem - zwane też zrzutem jądra).
- Dokładne zachowanie
signal()
różni się w zależności od systemu - a normy dopuszczają takie różnice.
Są to ogólnie dobre powody, dla których warto używać sigaction()
zamiast signal()
. Jednak interfejs programu sigaction()
jest niezaprzeczalnie bardziej skomplikowany.
Którykolwiek z nich używasz, nie daj się skusić alternatywnych interfejsów sygnałowych, takich jak
sighold()
,
sigignore()
,
sigpause()
i
sigrelse()
. Są nominalnie alternatywą dla sigaction()
, ale są ledwo znormalizowane i są obecne w POSIX dla kompatybilności wstecznej, a nie do poważnego użytku. Zauważ, że standard POSIX mówi, że ich zachowanie w programach wielowątkowych jest niezdefiniowane.
Programy i sygnały wielowątkowe to zupełnie inna skomplikowana historia. AFAIK, oba signal()
i sigaction()
są OK w aplikacjach wielowątkowych.
Cornstalks zauważa :
Strona podręcznika Linux dla signal()
mówi:
Skutki signal()
w procesie wielowątkowym są nieokreślone.
Dlatego myślę, że sigaction()
jest to jedyny, który można bezpiecznie używać w procesie wielowątkowym.
To interesujące. W tym przypadku strona podręcznika Linux jest bardziej restrykcyjna niż POSIX. POSIX określa signal()
:
Jeśli proces jest wielowątkowy lub jeśli proces jest jednowątkowy, a procedura obsługi sygnału jest wykonywana inaczej niż w wyniku:
- Powołanie proces
abort()
, raise()
, kill()
, pthread_kill()
, lub sigqueue()
, aby wygenerować sygnał, który nie jest zablokowany
- Oczekujący sygnał, który został odblokowany i dostarczony przed wywołaniem, które go odblokowało, powraca
zachowanie jest niezdefiniowane, jeśli program obsługi sygnału odnosi się do dowolnego obiektu innego niż errno
ze statycznym czasem przechowywania innym niż przypisanie wartości do obiektu zadeklarowanego jako volatile sig_atomic_t
, lub jeśli program obsługi sygnału wywołuje jakąkolwiek funkcję zdefiniowaną w tym standardzie, inną niż jedna z funkcji wymienionych w Koncepcje sygnałów .
Zatem POSIX jasno określa zachowanie signal()
w aplikacji wielowątkowej.
Niemniej jednak sigaction()
powinno być preferowane w zasadzie we wszystkich okolicznościach - a przenośny kod wielowątkowy powinien być używany, sigaction()
chyba że istnieje przytłaczający powód, dla którego nie może (na przykład „używaj tylko funkcji zdefiniowanych przez Standard C” - i tak, kod C11 może być wielowątkowy gwintowane). I tak właśnie jest w pierwszym akapicie tej odpowiedzi.
signal
dotyczy w rzeczywistości zachowania systemu Unix V. POSIX pozwala albo na to zachowanie, albo na znacznie bardziej rozsądne zachowanie BSD, ale ponieważ nie możesz być pewien, które z nich uzyskasz, nadal najlepiej jest go używaćsigaction
.SA_RESETHAND
teżSA_NODEFER
.sigaction()
, zasadniczo jesteś zobowiązany do korzystania ze specyfikacji Standard C dlasignal()
. Jednak daje to niezwykle zubożały zestaw opcji tego, co możesz zrobić. Możesz: modyfikować (zakres plików) zmienne typuvolatile sig_atomic_t
; wywołaj jedną z funkcji „szybkiego wyjścia” (_Exit()
,quick_exit()
) lubabort()
; wywołaniesignal()
z bieżącym numerem sygnału jako argumentem sygnału; powrót. I to wszystko. Nie ma gwarancji, że cokolwiek innego będzie przenośne. Jest to tak surowe, że większość ludzi ignoruje te zasady - ale wynikowy kod jest podejrzany.sigaction()
demo od samych GCC: gnu.org/software/libc/manual/html_node/… ; oraz doskonałesignal()
demo od samego GCC: gnu.org/software/libc/manual/html_node/… . Zauważ, że w wersjisignal
demonstracyjnej unikają zmiany funkcji obsługi z ignore (SIG_IGN
), jeśli taka była wcześniej celowo ustawiona.Dla mnie ta poniższa linijka wystarczyła do podjęcia decyzji:
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
Niezależnie od tego, czy zaczynasz od zera, czy modyfikujesz stary program, sigaction powinna być właściwą opcją.
źródło
Są to różne interfejsy dla urządzeń sygnalizacyjnych systemu operacyjnego. Należy preferować używanie sigaction do sygnalizowania, jeśli to możliwe, ponieważ signal () ma zachowanie zdefiniowane w implementacji (często podatne na wyścigi) i zachowuje się inaczej w systemach Windows, OS X, Linux i innych systemach UNIX.
Szczegółowe informacje można znaleźć w tej uwadze bezpieczeństwa .
źródło
signal () to standardowe C, sigaction () nie.
Jeśli możesz użyć jednego z nich (to znaczy jesteś w systemie POSIX), użyj sigaction (); nie jest określone, czy signal () resetuje procedurę obsługi, co oznacza, że aby być przenośnym, należy ponownie wywołać funkcję signal () wewnątrz tej funkcji. Co gorsza, jest wyścig: jeśli otrzymasz dwa sygnały w krótkich odstępach czasu, a drugi zostanie dostarczony przed ponowną instalacją programu obsługi, będziesz mieć domyślną akcję, która prawdopodobnie będzie polegała na zabiciu twojego procesu. Z drugiej strony sigaction () gwarantuje użycie „niezawodnej” semantyki sygnału. Nie musisz ponownie instalować programu obsługi, ponieważ nigdy nie zostanie on zresetowany. Dzięki SA_RESTART możesz również ustawić automatyczne ponowne uruchamianie niektórych wywołań systemowych (więc nie musisz ręcznie sprawdzać EINTR). sigaction () ma więcej opcji i jest niezawodny, dlatego zaleca się jego stosowanie.
Psst ... nie mów nikomu, że ci to powiedziałem, ale POSIX ma obecnie funkcję bsd_signal (), która działa jak signal (), ale zapewnia semantykę BSD, co oznacza, że jest niezawodna. Jego głównym zastosowaniem jest przenoszenie starych aplikacji, które zakładały niezawodne sygnały, a POSIX nie zaleca jego używania.
źródło
bsd_signal()
- niektóre implementacje POSIX mogą mieć tę funkcję, ale sam POSIX nie zawiera takiej funkcji (patrz POSIX ).W skrócie:
sigaction()
jest dobry i dobrze zdefiniowany, ale jest funkcją Linuksa, więc działa tylko w Linuksie.signal()
jest zły i słabo zdefiniowany, ale jest standardową funkcją C, więc działa na wszystkim.Co na ten temat mają do powiedzenia strony podręcznika Linux?
man 2 signal
(zobacz tutaj online ) stwierdza:Innymi słowy: nie używaj
signal()
. Użyjsigaction()
zamiast tego!Co myśli GCC?
Źródło: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Tak więc, jeśli zarówno Linux, jak i GCC mówią, żeby nie używać
signal()
, ale używaćsigaction()
zamiast tego, nasuwa się pytanie: jak u licha używamy tej mylącejsigaction()
rzeczy !?Przykłady użycia:
Przeczytaj DOSKONAŁY
signal()
przykład GCC tutaj: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-HandlingI ich DOSKONAŁY
sigaction()
przykład tutaj: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlPo przeczytaniu tych stron wymyśliłem następującą technikę
sigaction()
:1.
sigaction()
, ponieważ jest to właściwy sposób dołączania obsługi sygnału, jak opisano powyżej:2. I
signal()
nawet jeśli nie jest to dobry sposób na podłączenie modułu obsługi sygnału, jak opisano powyżej, nadal dobrze jest wiedzieć, jak go używać.Oto kod demonstracyjny GCC skopiowany i wklejony, ponieważ jest mniej więcej tak dobry, jak będzie:
Główne linki, o których należy pamiętać:
signal()
przykład użycia GCC : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handlingsigaction()
przykład użycia GCC : https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlsigemptyset()
isigfillset()
; Nadal nie rozumiem ich dokładnie, ale wiem, że są ważne: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.htmlZobacz też:
źródło
Ze strony podręcznika
signal(3)
:Oba wywołują ten sam instrument bazowy. Prawdopodobnie nie powinieneś manipulować odpowiedzią pojedynczego sygnału z obydwoma, ale mieszanie ich nie powinno powodować żadnych przerw ...
źródło
Sugerowałbym również użycie sigaction () nad signal () i chciałbym dodać jeszcze jeden punkt. sigaction () daje więcej opcji, takich jak pid procesu, który umarł (możliwe przy użyciu struktury siginfo_t).
źródło
Użyłbym signal (), ponieważ jest bardziej przenośny, przynajmniej w teorii. Zagłosuję na każdego komentatora, który wymyśli nowoczesny system, który nie ma warstwy kompatybilności z POSIX i obsługuje funkcję signal ().
Cytat z dokumentacji GLIBC :
źródło
Ze strony man signal (7)
I powiedziałbym, że ten „problem” istnieje dla sygnału (2) i sigaction (2) . Uważaj więc na sygnały i wątki.
... a signal (2) wydaje się wywoływać sigaction (2) underneath w Linuksie z glibc.
źródło