Kann das Signal ignoriert werden (verloren gehen)?

9

Ich habe eine Anwendung, die mit Arbeitern über Signale kommuniziert (insbesondere SIGUSR1 / SIGUSR2 / SIGSTOP).

Kann ich darauf vertrauen, dass jedes Signal vom Handler geliefert und verarbeitet wird?

Was passiert, wenn Signale schneller gesendet werden, als es für die Anwendung nicht möglich ist, sie zu verarbeiten (z. B. aufgrund der momentan hohen Hostlast)?

KaP
quelle

Antworten:

8

Abgesehen von dem Problem "zu viele Signale" können Signale explizit ignoriert werden. Von 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.

Signale können auch blockiert werden. Von 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.

Sowohl blockierte als auch ignorierte Signalmengen werden von untergeordneten Prozessen geerbt. Daher kann es vorkommen, dass der übergeordnete Prozess Ihrer Anwendung eines dieser Signale ignoriert oder blockiert hat.

Was passiert, wenn mehrere Signale geliefert werden, bevor der Prozess die Verarbeitung der vorherigen beendet hat? Das hängt vom Betriebssystem ab. Die signal(2)oben verlinkte Manpage beschreibt dies:

  • System V würde die Signaldisposition auf die Standardeinstellung zurücksetzen. Schlimmer noch, eine schnelle Übermittlung mehrerer Signale würde zu rekursiven (?) Aufrufen führen.
  • BSD würde das Signal automatisch blockieren, bis der Handler fertig ist.
  • Unter Linux hängt dies von den für GNU gesetzten Kompilierungsflags ab libc, aber ich würde das BSD-Verhalten erwarten.
muru
quelle
4
In der Manpage von Linux wird ausdrücklich signal(2)darauf hingewiesen, dass Sie diese Verwirrung vermeiden, indem Sie sigaction(2)stattdessen verwenden.
Nate Eldredge
7

Sie können nicht darauf vertrauen, dass jedes gesendete Signal zugestellt wird. Beispielsweise "verschmilzt" der Linux-Kernel SIGCHLD, wenn ein Prozess bei der Verarbeitung von SIGCHLD aus einem verlassenen untergeordneten Prozess lange dauert.

Um einen anderen Teil Ihrer Frage zu beantworten, werden Signale im Kernel "in die Warteschlange gestellt", wenn mehrere verschiedene Signale in einem zu kurzen Intervall eintreffen.

Sie sollten verwenden sigaction(), um den Signalhandler mit dem sa_sigactionMitglied von einzurichten und siginfo_tdas sa_maskMitglied des siginfo_tArguments sorgfältig festzulegen. Ich denke, dies bedeutet, zumindest alle "asynchronen" Signale zu maskieren. Laut der Manpage für Linux sigaction()maskieren Sie auch das Signal, das verarbeitet wird. Ich denke, Sie sollten das sa_flagsMitglied auf SA_SIGINFO setzen, aber ich kann mich nicht erinnern, warum ich diesen Aberglauben habe. Ich glaube, dies wird Ihrem Prozess einen Signalhandler geben, der ohne Rennbedingungen eingestellt bleibt und der nicht von den meisten anderen Signalen unterbrochen wird.

Schreiben Sie Ihre Signalhandlerfunktion sehr, sehr sorgfältig. Stellen Sie einfach eine globale Variable ein, um anzuzeigen, dass ein Signal abgefangen wurde, und lassen Sie den Rest des Prozesses die gewünschte Aktion für dieses Signal ausführen. Auf diese Weise werden die Signale für die geringste Zeit maskiert.

Außerdem sollten Sie Ihren Signalverarbeitungscode sehr gründlich testen. Stellen Sie es in einen kleinen Testprozess und senden Sie so viele SIGUSR1- und SIGUSR2-Signale wie möglich, möglicherweise von 2 oder 3 speziellen Signal-Sendeprogrammen. Mischen Sie auch einige andere Signale ein, nachdem Sie sicher sind, dass Ihr Code SIGUSR1 und SIGUSR2 schnell und korrekt verarbeiten kann. Bereiten Sie sich auf schwieriges Debuggen vor.

Wenn Sie Linux und nur Linux verwenden, können Sie signalfd()einen Dateideskriptor erstellen, den Sie abrufen select()oder abfragen können, um diese Signale zu empfangen. Die Verwendung signalfd()erleichtert möglicherweise das Debuggen.

Bruce Ediger
quelle
2
Es ist nicht nur SIGCLD, das zusammengeführt wird: Alle Signale werden möglicherweise zusammengeführt, wenn sie geliefert werden, bevor sie verarbeitet werden können.
Gilles 'SO - hör auf böse zu sein'
Gibt es ein Maß dafür, wie lange "zu lang" für SIGCHLD-Signale ist? Ich habe dieses Verhalten gerade in meinem Programm und mein Signalhandler benötigt nicht mehr als ~ 100 ms, wie ich erwarten würde.
Xrisk
@Rishav - meines Wissens gibt es keine Möglichkeit herauszufinden, was "zu lang" ist. Ich würde erwarten, dass die Gesamtsystemlast wichtig ist. Das heißt, was andere Prozesse und der Kernel tun, würde "wie lange" zwischen den Signalen beeinflussen, damit sie zusammenwachsen. Keine hilfreiche Antwort, denke ich.
Bruce Ediger
6

Es wird garantiert, dass ein Signal in dem Sinne geliefert wird, dass ein Prozess erfolgreich aufgerufen wird killdann empfängt das Ziel das Signal. Dies ist asynchron: Der Absender kann nicht wissen, wann das Signal empfangen oder verarbeitet wird. Dies garantiert jedoch nicht, dass das Signal geliefert wird. Das Ziel könnte sterben, bevor es das Signal verarbeiten kann. Wenn das Ziel das Signal zum Zeitpunkt der Übermittlung ignoriert, hat das Signal keine Auswirkung. Wenn das Ziel mehrere Instanzen derselben Signalnummer empfängt, bevor es sie verarbeiten kann, können (und werden) die Signale zusammengeführt: Wenn Sie dasselbe Signal zweimal an einen Prozess senden, können Sie nicht wissen, ob der Prozess das Signal empfängt ein-oder zweimal. Signale dienen hauptsächlich dazu, einen Prozess abzubrechen oder einen Prozess aufmerksam zu machen. Sie sind nicht für die Kommunikation als solche konzipiert.

Wenn Sie eine zuverlässige Lieferung benötigen, benötigen Sie einen anderen Kommunikationsmechanismus. Es gibt zwei Hauptkommunikationsmechanismen zwischen Prozessen: Eine Pipe ermöglicht eine unidirektionale Kommunikation; Ein Socket ermöglicht die bidirektionale Kommunikation und mehrere Verbindungen zum selben Server. Wenn das Ziel so viele Benachrichtigungen verarbeiten soll, wie Sie es senden, senden Sie Bytes über eine Pipe.

Gilles 'SO - hör auf böse zu sein'
quelle
4
Wollten Sie "Ein Signal wird garantiert geliefert" schreiben, da Sie einige der Möglichkeiten beschrieben haben, wie das Signal nicht geliefert werden würde (dh der Prozess ist vor dem Empfang abgestorben oder die Signale wurden zusammengeführt)?
Johnny
2

Der Kernel kann Standardsignale zusammenführen, wenn mehr als eines im blockierten Zustand geliefert wird. Echtzeitsignale sind dagegen nicht ähnlich behindert.

Aus der Handbuchseite von Signal (7) :

Echtzeitsignale unterscheiden sich durch Folgendes:

  1. Es können mehrere Instanzen von Echtzeitsignalen in die Warteschlange gestellt werden. Wenn dagegen mehrere Instanzen eines Standardsignals geliefert werden, während dieses Signal derzeit blockiert ist, wird nur eine Instanz in die Warteschlange gestellt.

Versuchen Sie es mit einem Signal mit einer Nummer im Bereich von SIGRTMIN bis SIGRTMAX.

Graham Rushton
quelle
Es gibt ein Limit für Echtzeitsignale, aber es ist ziemlich hoch. Ein Signal wird gelöscht, wenn die Anzahl der vom Benutzer gesendeten ausstehenden ausstehenden Signale RLIMIT_SIGPENDING überschreitet. ulimit -izeigt diesen Wert als 63432 unter Ubuntu 18.04.
Bain