std::signal
| Definiert im Header <csignal>
|
||
/*signal-handler*/* signal( int sig, /*signal-handler*/* handler );
|
(1) | |
extern "C" using /*signal-handler*/ = void(int);
|
(2) | (nur zur Veranschaulichung*) |
Ändert die Behandlung des Signals sig. Abhängig vom Wert von handler kann das Signal ignoriert, auf die Standardbehandlung zurückgesetzt oder von einer benutzerdefinierten Funktion behandelt werden, die als (*handler)(sig) aufgerufen wird.
Wenn der Signalhandler auf eine Funktion gesetzt ist und ein Signal auftritt, ist es implementierungsdefiniert, ob std::signal(sig, SIG_DFL) unmittelbar vor dem Start des Signalhandlers ausgeführt wird. Außerdem kann die Implementierung das Auftreten einer implementierungsdefinierten Menge von Signalen verhindern, während der Signalhandler läuft.
Für einige der Signale kann die Implementierung std::signal(sig, SIG_IGN) beim Start des Programms aufrufen. Für die übrigen muss die Implementierung std::signal(sig, SIG_DFL) aufrufen.
(Hinweis: POSIX führte sigaction ein, um diese implementierungsdefinierten Verhaltensweisen zu standardisieren.)
Parameter
| sig | - | das Signal, für das der Signalhandler festgelegt werden soll. Es kann ein implementierungsdefinierter Wert oder einer der folgenden Werte sein:
| ||||||
| handler | - | der Signalhandler. Dies muss einer der folgenden sein:
|
Rückgabewert
Vorheriger Signal-Handler bei Erfolg oder SIG_ERR bei Fehler (das Setzen eines Signal-Handlers kann auf einigen Implementierungen deaktiviert sein).
Signal-Handler
Die folgenden Einschränkungen gelten für die benutzerdefinierte Funktion, die als Signal-Handler installiert wird.
|
Wenn der Signalhandler NICHT als Ergebnis von std::abort oder std::raise (asynchrones Signal) aufgerufen wird, ist das Verhalten undefiniert, falls
|
(bis C++17) |
|
Eine einfache lockfreie atomare Operation ist ein Aufruf einer Funktion f aus <atomic> oder <stdatomic.h> (seit C++23) , sodass:
Das Verhalten ist undefiniert, wenn ein Signalhandler eine der folgenden Aktionen ausführt:
|
(seit C++17) |
Wenn die benutzerdefinierte Funktion bei der Behandlung von SIGFPE , SIGILL , SIGSEGV oder anderen implementierungsdefinierten Signalen, die eine Rechenausnahme spezifizieren, zurückkehrt, ist das Verhalten undefiniert.
Wenn der Signalhandler als Ergebnis von std::abort oder std::raise (synchrones Signal) aufgerufen wird, ist das Verhalten undefiniert, wenn der Signalhandler std::raise aufruft.
|
Beim Eintritt in den Signal-Handler ist der Zustand der Gleitkommaumgebung und die Werte aller Objekte nicht spezifiziert, außer für
Bei der Rückkehr von einem Signal-Handler ist der Wert jedes Objekts, das durch den Signal-Handler geändert wurde und nicht volatile std:: sig_atomic_t oder lock-free std::atomic ist, unbestimmt. |
(bis C++14) | ||
|
Ein Aufruf der Funktion
Wenn ein Signal-Handler als Ergebnis eines Aufrufs von
std::raise
ausgeführt wird (synchron), dann ist die Ausführung des Handlers
sequenced-after
dem Aufruf von
Zwei Zugriffe auf dasselbe Objekt vom Typ volatile std:: sig_atomic_t führen nicht zu einem Data Race, wenn beide im selben Thread auftreten, selbst wenn einer oder mehrere in einem Signal-Handler auftreten. Für jeden Signal-Handler-Aufruf können die Auswertungen, die durch den Thread durchgeführt werden, der einen Signal-Handler aufruft, in zwei Gruppen A und B unterteilt werden, sodass keine Auswertungen in B happen-before Auswertungen in A, und die Auswertungen solcher volatile std:: sig_atomic_t Objekte Werte annehmen, als ob alle Auswertungen in A happened-before der Ausführung des Signal-Handlers und die Ausführung des Signal-Handlers happened-before allen Auswertungen in B. |
(seit C++14) |
Anmerkungen
POSIX verlangt, dass signal threadsicher ist, und spezifiziert eine Liste von asynchron-signal-sicheren Bibliotheksfunktionen, die von jedem Signalhandler aufgerufen werden dürfen.
Es wird erwartet, dass Signalhandler C-Verknüpfung haben und im Allgemeinen nur die Funktionen aus der gemeinsamen Teilmenge von C und C++ verwenden. Übliche Implementierungen erlauben jedoch eine Funktion mit C++-Verknüpfung als Signalhandler.
Beispiel
#include <csignal> #include <iostream> namespace { volatile std::sig_atomic_t gSignalStatus; } void signal_handler(int signal) { gSignalStatus = signal; } int main() { // Installiere einen Signal-Handler std::signal(SIGINT, signal_handler); std::cout << "SignalValue: " << gSignalStatus << '\n'; std::cout << "Sending signal: " << SIGINT << '\n'; std::raise(SIGINT); std::cout << "SignalValue: " << gSignalStatus << '\n'; }
Mögliche Ausgabe:
SignalValue: 0 Sending signal: 2 SignalValue: 2
Referenzen
- C++23-Standard (ISO/IEC 14882:2024):
-
- 17.13.5 Signal-Handler [support.signal]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 17.13.5 Signal-Handler [support.signal]
- C++17-Standard (ISO/IEC 14882:2017):
-
- 21.10.4 Signal-Handler [support.signal]
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| LWG 3756 | C++17 | es war unklar, ob std::atomic_flag signal-sicher ist | es ist |
Siehe auch
|
führt den Signal-Handler für ein bestimmtes Signal aus
(Funktion) |
|
|
(C++11)
|
Barriere zwischen einem Thread und einem Signal-Handler, der im selben Thread ausgeführt wird
(Funktion) |
|
C-Dokumentation
für
signal
|
|