it-swarm.com.de

Was ist der Unterschied zwischen Signalisierung und Signalisierung?

Ich wollte gerade einen zusätzlichen Signal-Handler zu einer App hinzufügen, die wir hier haben, und ich habe bemerkt, dass der Autor sigaction() verwendet hat, um die anderen Signal-Handler einzurichten. Ich wollte signal() verwenden. Um der Konvention zu folgen, sollte ich sigaction() verwenden, aber wenn ich von Grund auf schreiben würde, welche sollte ich wählen?

118
MattSmith

Verwenden Sie sigaction() , es sei denn, Sie haben sehr zwingende Gründe, dies nicht zu tun.

Die Schnittstelle signal() hat das Altertum (und damit die Verfügbarkeit) zu ihren Gunsten und ist im C-Standard definiert. Dennoch weist es eine Reihe unerwünschter Eigenschaften auf, die sigaction() vermeidet - es sei denn, Sie verwenden die zu sigaction() ausdrücklich hinzugefügten Flags, um das alte Verhalten von signal() getreu zu simulieren.

  1. Die Funktion signal() blockiert (notwendigerweise) nicht das Eintreffen anderer Signale, während der aktuelle Handler ausgeführt wird. sigaction() kann andere Signale blockieren, bis der aktuelle Handler zurückkehrt.
  2. Die Funktion signal() setzt (normalerweise) die Signalaktion für fast alle Signale auf SIG_DFL (Standard) zurück. Dies bedeutet, dass sich der signal()-Handler als erste Aktion neu installieren muss. Es öffnet sich auch ein Fenster der Sicherheitsanfälligkeit zwischen dem Zeitpunkt, zu dem das Signal erkannt und der Handler erneut installiert wird. Wenn eine zweite Instanz des Signals eintrifft, tritt das Standardverhalten auf (in der Regel beendet, manchmal mit Vorurteilen - auch als Core-Dump bezeichnet).
  3. Das genaue Verhalten von signal() variiert zwischen den Systemen - und die Standards erlauben diese Variationen.

Dies sind im Allgemeinen gute Gründe für die Verwendung von sigaction() anstelle von signal(). Die Schnittstelle von sigaction() ist jedoch zweifellos komplizierter.

Welche von beiden Sie auch verwenden, lassen Sie sich nicht von alternativen Signalschnittstellen wie sighold() , sigignore() , sigpause() und sigrelse() . Sie sind nominell Alternativen zu sigaction(), aber sie sind kaum standardisiert und in POSIX eher aus Gründen der Abwärtskompatibilität als zur ernsthaften Verwendung vorhanden. Beachten Sie, dass der POSIX-Standard angibt, dass sein Verhalten in Multithread-Programmen undefiniert ist.

Multithread-Programme und -Signale sind eine andere komplizierte Geschichte. AFAIK, sowohl signal() als auch sigaction() sind in Multithread-Anwendungen in Ordnung.

Cornstalksbeobachtet :

Die Linux-Manpage für signal() sagt:

Die Auswirkungen von signal() in einem Multithread-Prozess sind nicht angegeben.

Daher denke ich, dass sigaction() das einzige ist, das in einem Multithread-Prozess sicher verwendet werden kann.

Das ist interessant. Die Linux-Handbuchseite ist in diesem Fall restriktiver als POSIX. POSIX gibt an für signal() :

Wenn es sich um einen Multithread-Prozess handelt oder wenn es sich um einen Single-Thread-Prozess handelt und ein Signal-Handler ausgeführt wird, der sich nicht aus folgenden Gründen ergibt:

  • Der Prozess, der abort(), raise(), kill(), pthread_kill() oder sigqueue() aufruft, um ein Signal zu generieren, das nicht blockiert ist
  • Ein anstehendes Signal wird entsperrt und zugestellt, bevor der entsperrende Anruf zurückkommt

das Verhalten ist undefiniert, wenn der Signalhandler auf ein anderes Objekt als errno mit einer anderen statischen Speicherdauer verweist, als indem einem als volatile sig_atomic_t deklarierten Objekt ein Wert zugewiesen wird, oder wenn der Signalhandler eine in definierte Funktion aufruft dieser Standard ist nicht eine der in Signalkonzepte aufgeführten Funktionen.

So spezifiziert POSIX eindeutig das Verhalten von signal() in einer Multithread-Anwendung.

Dennoch ist sigaction() im Wesentlichen unter allen Umständen zu bevorzugen - und portabler Multithread-Code sollte sigaction() verwenden, es sei denn, es gibt einen überwältigenden Grund, warum dies nicht möglich ist (z. B. "Nur Funktionen verwenden, die in Standard C definiert sind" - und ja, C11-Code kann dies Multithreading sein). Welches ist im Grunde, was der erste Absatz dieser Antwort auch sagt.

150

Sie sind verschiedene Schnittstellen für die Signaleinrichtungen von OS. Sie sollten sigaction vorziehen, wenn möglich zu signalisieren, da signal () ein implementierungsdefiniertes (oft rassenanfälliges) Verhalten aufweist und sich auf Windows-, OS X-, Linux- und anderen UNIX-Systemen unterschiedlich verhält.

Weitere Informationen finden Sie in diesem Sicherheitshinweis .

5
ididak

Für mich war diese untere Zeile genug, um zu entscheiden:

Die Funktion sigaction () bietet eine umfassender und zuverlässiger Mechanismus zum Steuern von Signalen; Neu Anwendungen sollten sigaction () .__ verwenden. anstatt Signal ()

http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07

Unabhängig davon, ob Sie bei Null anfangen oder ein altes Programm ändern, sollte sigaction die richtige Option sein.

4
San

signal () ist standard C, sigaction () nicht.

Wenn Sie beide verwenden können (dh Sie sind auf einem POSIX-System), verwenden Sie sigaction (); Es ist nicht festgelegt, ob signal () den Handler zurücksetzt. Das heißt, um tragbar zu sein, müssen Sie signal () erneut im Handler aufrufen. Schlimmer ist, dass es ein Rennen gibt: Wenn Sie zwei Signale in schneller Folge erhalten und das zweite geliefert wird, bevor Sie den Handler erneut installieren, haben Sie die Standardaktion, die wahrscheinlich dazu führen wird, Ihren Prozess zu beenden. sigaction () verwendet dagegen eine "zuverlässige" Signalsemantik. Sie müssen den Handler nicht erneut installieren, da er niemals zurückgesetzt wird. Mit SA_RESTART können Sie auch einige Systemaufrufe zum automatischen Neustart abrufen (damit Sie nicht manuell nach EINTR suchen müssen) sigaction () hat mehr Optionen und ist zuverlässig, sodass die Verwendung ermutigt wird.

Psst ... sagen Sie niemandem, dass ich Ihnen dies erzählt habe, aber POSIX hat derzeit eine Funktion bsd_signal (), die wie signal () wirkt, aber BSD-Semantik gibt, was bedeutet, dass sie zuverlässig ist. Die Hauptanwendung ist für die Portierung alter Anwendungen, die zuverlässige Signale voraussetzen, und POSIX empfiehlt nicht, sie zu verwenden.

3
Huzzefakhan

Von dersignal(3)man-Seite:

BESCHREIBUNG

 This signal() facility is a simplified interface to the more
 general sigaction(2) facility.

Beide rufen dieselbe zugrundeliegende Einrichtung auf. Sie sollten vermutlich nicht die Antwort eines einzelnen Signals mit beiden manipulieren, aber das Mischen der beiden sollte nicht dazu führen, dass irgendetwas bricht ...

2
dmckee

Ich würde auch vorschlagen, sigaction () über signal () zu verwenden, und ich möchte einen weiteren Punkt hinzufügen Sigaction () gibt Ihnen mehr Optionen, wie beispielsweise die PID des Prozesses, der gestorben ist (möglich mit der Struktur siginfo_t).

1

Ich würde signal () verwenden, da es zumindest in der Theorie tragbarer ist. Ich stimme jedem Kommentator zu, der mit einem modernen System aufwarten kann, das keine POSIX-Kompatibilitätsebene hat und signal () unterstützt.

Zitieren aus der GLIBC-Dokumentation :

Es ist möglich, sowohl die Signal- als auch die Siggierungsfunktion in .__ zu verwenden. ein einzelnes Programm, aber Sie müssen vorsichtig sein, da sie interagieren auf etwas seltsame Weise.

Die Funktion sigaction gibt mehr Informationen an als das Signal Funktion, so dass der Rückgabewert vom Signal nicht den vollen Wert ausdrücken kann Reihe von Unterscheidungsmöglichkeiten. Wenn Sie also ein Signal für .__ verwenden. Wenn Sie eine Aktion speichern und später wieder herstellen, kann sie möglicherweise nicht Richten Sie einen mit sigaction eingerichteten Handler ordnungsgemäß ein.

Um Probleme zu vermeiden, verwenden Sie immer sigaction zum Speichern von und stellen Sie einen Handler wieder her, wenn Ihr Programm überhaupt eine Signatur verwendet. Schon seit sigaction ist allgemeiner, es kann jedes .__ richtig speichern und wieder herstellen. Aktion, unabhängig davon, ob sie ursprünglich mit .__ erstellt wurde. Signal oder Signal.

Auf einigen Systemen, wenn Sie eine Aktion mit Signal und dann .__ festlegen. Untersuchen Sie es mit sigaction, die Handler-Adresse, die Sie erhalten, darf nicht das gleiche sein, was Sie mit signal angegeben haben. Es kann nicht einmal sein geeignet als Aktionsargument mit Signal. Aber Sie können sich darauf verlassen. auf die Verwendung als Argument zur Unterscheidung. Dieses Problem tritt niemals auf auf dem GNU System.

Daher ist es besser, den einen oder den anderen Mechanismus zu verwenden konsistent innerhalb eines einzigen Programms.

Portabilität Hinweis: Die grundlegende Signalfunktion ist eine Funktion von ISO C, während sigaction zum POSIX.1-Standard gehört. Wenn du bist besorgt über die Portabilität auf Nicht-POSIX-Systeme, dann sollten Sie Verwenden Sie stattdessen die Signalfunktion.

Copyright (C) 1996-2008 Free Software Foundation, Inc.

Es wird die Erlaubnis erteilt, das Dokument zu kopieren, zu verteilen und/oder zu ändern Dokument unter den Bedingungen der GNU Free Documentation License, Version 1.2 oder eine neuere Version, die von der Freien Software veröffentlicht wird Stiftung; ohne Invariante Abschnitte, ohne Frontcover-Texte, und ohne Back-Cover-Texte. Eine Kopie der Lizenz ist in .__ enthalten. der Abschnitt mit dem Titel "GNU Free Documentation License".

1
bmdhacks

Von Manpage Signal (7)

Ein prozessorientiertes Signal kann an ein beliebiges Signal gesendet werden. einer der Threads, die das Signal derzeit nicht blockiert haben . Wenn mehr als einer der Threads das Signal aufgehoben hat, wird der Der Kernel wählt einen beliebigen Thread aus, an den das Signal gesendet werden soll.

Und ich würde sagen, diese "Ausgabe" existiert für Signal (2) und Sigaction (2) . Seien Sie also vorsichtig mit Signalen und Threads.

... und signal (2) scheint unter Linux sigaction (2) unter Linux mit glibc aufzurufen.

0
robert.berger