Namespaces
Variants

std:: signal

From cppreference.net
Utilities library
Défini dans l'en-tête <csignal>
/* signal-handler */ * signal ( int sig, /* signal-handler */ * handler ) ;
(1)
extern "C" using /* signal-handler */ = void ( int ) ;
(2) ( exposition uniquement* )

Modifie la gestion du signal sig . Selon handler , le signal peut être ignoré, défini par défaut ou traité par une fonction définie par l'utilisateur.

Lorsqu'un gestionnaire de signal est défini sur une fonction et qu'un signal se produit, il est défini par l'implémentation si std :: signal ( sig, SIG_DFL ) sera exécuté immédiatement avant le début du gestionnaire de signal. De plus, l'implémentation peut empêcher un ensemble défini par l'implémentation de signaux de se produire pendant l'exécution du gestionnaire de signal.

Pour certains signaux, l'implémentation peut appeler std :: signal ( sig, SIG_IGN ) au démarrage du programme. Pour les autres, l'implémentation doit appeler std :: signal ( sig, SIG_DFL ) .

(Note : POSIX a introduit sigaction pour standardiser ces comportements définis par l'implémentation)

Table des matières

Paramètres

sig - le signal auquel définir le gestionnaire de signal. Il peut s'agir d'une valeur définie par l'implémentation ou d'une des valeurs suivantes :
définit les types de signaux
(constante macro)
handler - le gestionnaire de signal. Ce doit être l'un des éléments suivants :
  • SIG_DFL macro. Le gestionnaire de signal est défini sur le gestionnaire de signal par défaut.
  • SIG_IGN macro. Le signal est ignoré.
  • Un pointeur vers une fonction. La signature de la fonction doit être équivalente à ce qui suit :
extern "C" void fun ( int sig ) ;


Valeur de retour

Gestionnaire de signal précédent en cas de succès ou SIG_ERR en cas d'échec (la configuration d'un gestionnaire de signal peut être désactivée sur certaines implémentations).

Gestionnaire de signal

Les limitations suivantes sont imposées à la fonction définie par l'utilisateur qui est installée comme gestionnaire de signal.

Si le gestionnaire de signal est appelé NON comme résultat de std::abort ou std::raise (signal asynchrone), le comportement est indéfini si

  • le gestionnaire de signal appelle toute fonction de la bibliothèque standard, sauf
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal avec le premier argument étant le numéro du signal actuellement traité (le gestionnaire asynchrone peut se réenregistrer lui-même, mais pas d'autres signaux).
  • le gestionnaire de signal fait référence à tout objet avec une durée de stockage statique qui n'est pas std::atomic ou (depuis C++11) volatile std:: sig_atomic_t .
(jusqu'à C++17)

Une opération atomique simple sans verrouillage est un appel d'une fonction f de <atomic> ou <stdatomic.h> (depuis C++23) , telle que :

Le comportement est indéfini si un gestionnaire de signal effectue l'une des actions suivantes :

  • appel à toute fonction de bibliothèque, sauf pour les opérations atomiques simples sans verrouillage et les fonctions sûres pour les signaux suivantes (noter, en particulier, que l'allocation dynamique n'est pas sûre pour les signaux) :
  • accès à un objet avec une durée de stockage de thread
  • une expression dynamic_cast
  • une expression throw
  • entrée dans un try block
  • initialisation d'une variable statique qui effectue une initialisation dynamique non locale (y compris retardée jusqu'à la première utilisation ODR)
  • attend la fin de l'initialisation de toute variable avec une durée de stockage statique due à son initialisation concurrente par un autre thread
(depuis C++17)

Si la fonction définie par l'utilisateur retourne lors du traitement de SIGFPE , SIGILL , SIGSEGV ou tout autre signal défini par l'implémentation spécifiant une exception de calcul, le comportement est indéfini.

Si le gestionnaire de signal est appelé suite à std::abort ou std::raise (signal synchrone), le comportement est indéfini si le gestionnaire de signal appelle std::raise .

À l'entrée du gestionnaire de signal, l'état de l'environnement à virgule flottante et les valeurs de tous les objets sont non spécifiés, sauf pour

(depuis C++11)

Au retour d'un gestionnaire de signal, la valeur de tout objet modifié par le gestionnaire de signal qui n'est pas volatile std:: sig_atomic_t ou std::atomic sans verrouillage est indéterminée.

(jusqu'à C++14)

Un appel à la fonction signal() se synchronise-avec toute invocation résultante du gestionnaire de signal.

Si un gestionnaire de signal est exécuté à la suite d'un appel à std::raise (de manière synchrone), alors l'exécution du gestionnaire est séquencée-après l'invocation de std::raise et séquencée-avant le retour de celle-ci, et s'exécute sur le même thread que std::raise . L'exécution des gestionnaires pour d'autres signaux est non séquencée par rapport au reste du programme et s'exécute sur un thread non spécifié.

Deux accès au même objet de type volatile std:: sig_atomic_t n'entraînent pas de course de données s'ils se produisent dans le même thread, même si un ou plusieurs se produisent dans un gestionnaire de signal. Pour chaque invocation de gestionnaire de signal, les évaluations effectuées par le thread invoquant un gestionnaire de signal peuvent être divisées en deux groupes A et B, de sorte qu'aucune évaluation dans B ne se produit-avant les évaluations dans A, et les évaluations de ces volatile std:: sig_atomic_t prennent des valeurs comme si toutes les évaluations dans A se produisaient-avant l'exécution du gestionnaire de signal et l'exécution du gestionnaire de signal se produisait-avant toutes les évaluations dans B.

(depuis C++14)

Notes

POSIX exige que signal soit thread-safe, et spécifie une liste de fonctions de bibliothèque asynchrone-signal-sûres qui peuvent être appelées depuis n'importe quel gestionnaire de signal.

Les gestionnaires de signal sont censés avoir une liaison C et, en général, n'utiliser que les fonctionnalités du sous-ensemble commun du C et du C++. Cependant, les implémentations courantes permettent d'utiliser une fonction avec une liaison C++ comme gestionnaire de signal.

Exemple

#include <csignal>
#include <iostream>
namespace
{
    volatile std::sig_atomic_t gSignalStatus;
}
void signal_handler(int signal)
{
    gSignalStatus = signal;
}
int main()
{
    // Installer un gestionnaire de signal
    std::signal(SIGINT, signal_handler);
    std::cout << "SignalValue: " << gSignalStatus << '\n';
    std::cout << "Sending signal: " << SIGINT << '\n';
    std::raise(SIGINT);
    std::cout << "SignalValue: " << gSignalStatus << '\n';
}

Sortie possible :

SignalValue: 0
Sending signal: 2
SignalValue: 2

Références

  • Norme C++23 (ISO/CEI 14882:2024) :
  • 17.13.5 Gestionnaires de signaux [support.signal]
  • Norme C++20 (ISO/CEI 14882:2020) :
  • 17.13.5 Gestionnaires de signaux [support.signal]
  • Norme C++17 (ISO/IEC 14882:2017) :
  • 21.10.4 Gestionnaires de signaux [support.signal]

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Applicable à Comportement publié Comportement corrigé
LWG 3756 C++17 il n'était pas clair si std::atomic_flag est sûr pour les signaux il l'est

Voir aussi

exécute le gestionnaire de signal pour un signal particulier
(fonction)
barrière entre un thread et un gestionnaire de signal exécuté dans le même thread
(fonction)
Documentation C pour signal