Abgesehen von dem Problem "zu viele Signale" können Signale explizit ignoriert werden. Ab 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. Ab 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 Signalsätze werden von untergeordneten Prozessen geerbt, daher kann es vorkommen, dass der übergeordnete Prozess Ihrer Anwendung eines dieser Signale ignoriert oder blockiert.
Was passiert, wenn mehrere Signale geliefert werden, bevor der Prozess die Verarbeitung der vorherigen abgeschlossen hat? Das hängt vom Betriebssystem ab. Die signal(2)
Die oben verlinkte Manpage beschreibt es:
- System V würde die Signaldisposition auf die Voreinstellung zurücksetzen. Schlimmer noch, die schnelle Lieferung 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 Kompilierungs-Flags ab, die für GNU
libc
gesetzt sind , aber ich würde das BSD-Verhalten erwarten.
Sie können nicht darauf vertrauen, dass jedes gesendete Signal zugestellt wird. Der Linux-Kernel "verschmilzt" beispielsweise SIGCHLD, wenn ein Prozess lange Zeit braucht, um SIGCHLD von einem beendeten untergeordneten Prozess zu verarbeiten.
Um einen anderen Teil Ihrer Frage zu beantworten, werden Signale innerhalb des Kernels "in die Warteschlange" gestellt, wenn eine Reihe verschiedener Signale in einem zu kurzen Intervall eintreffen.
Sie sollten sigaction()
verwenden um den Signalhandler mit dem sa_sigaction
einzurichten Mitglied von siginfo_t
, indem Sie sa_mask
festlegen Mitglied der siginfo_t
sorgfältig argumentieren. Ich denke, das bedeutet, zumindest alle "asynchronen" Signale zu maskieren. Laut der Manpage für Linux sigaction()
, maskieren Sie auch das verarbeitete Signal. Ich denke, Sie sollten den sa_flags
setzen Mitglied bei SA_SIGINFO, aber ich kann mich nicht erinnern, warum ich diesen Aberglauben habe. Ich glaube, dies wird Ihrem Prozess einen Signal-Handler geben, der ohne Rennbedingungen eingestellt bleibt und nicht durch die meisten anderen Signale unterbrochen wird.
Schreiben Sie Ihre Signal-Handler-Funktion sehr, sehr sorgfältig. Setzen Sie im Grunde einfach eine globale Variable, um anzuzeigen, dass ein Signal abgefangen wurde, und lassen Sie den Rest des Prozesses die gewünschte Aktion für dieses Signal ausführen. Signale werden auf diese Weise für die kürzeste Zeit maskiert.
Außerdem sollten Sie Ihren Signalbehandlungscode sehr gründlich testen. Setzen Sie es in einen kleinen Testprozess und senden Sie so viele SIGUSR1- und SIGUSR2-Signale wie möglich, vielleicht von 2 oder 3 speziellen Signalsendeprogrammen. 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 Debugging vor.
Wenn Sie Linux und nur Linux verwenden, sollten Sie darüber nachdenken, signalfd()
zu verwenden um einen Dateideskriptor zu erstellen, den Sie select()
können oder abfragen, um diese Signale zu empfangen. Mit signalfd()
könnte das Debuggen erleichtern.
Es wird garantiert, dass ein Signal geliefert wird, in dem Sinne, dass wenn ein Prozess kill
erfolgreich aufruft , dann empfängt das Ziel das Signal. Dies ist asynchron:Der Sender hat keine Möglichkeit zu 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 Lieferung ignoriert, hat das Signal keine Wirkung. Wenn das Ziel mehrere Instanzen derselben Signalnummer empfängt, bevor es sie verarbeiten kann, werden die Signale möglicherweise (und werden normalerweise) zusammengeführt:Wenn Sie dasselbe Signal zweimal an einen Prozess senden, können Sie nicht wissen, ob der Prozess das Signal empfangen wird ein-oder zweimal. Signale sind hauptsächlich darauf ausgelegt, einen Prozess zu beenden oder einen Prozess aufmerksam zu machen, sie sind nicht für die Kommunikation als solche konzipiert.
Wenn Sie eine zuverlässige Zustellung 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 eine bidirektionale Kommunikation und mehrere Verbindungen zum selben Server. Wenn Sie möchten, dass das Ziel so viele Benachrichtigungen verarbeitet, wie Sie es senden, senden Sie Bytes über eine Pipe.