Namespaces
Variants

std:: signal

From cppreference.net
Utilities library
Definido en el encabezado <csignal>
/* signal-handler */ * signal ( int sig, /* signal-handler */ * handler ) ;
(1)
extern "C" using /* signal-handler */ = void ( int ) ;
(2) ( solo para exposición* )

Cambia el manejo de la señal sig . Dependiendo de handler , la señal puede ser ignorada, establecida a valores predeterminados o manejada por una función definida por el usuario.

Cuando el manejador de señales se establece a una función y ocurre una señal, está definido por la implementación si std :: signal ( sig, SIG_DFL ) se ejecutará inmediatamente antes del inicio del manejador de señales. Además, la implementación puede prevenir que ocurra algún conjunto de señales definido por la implementación mientras se ejecuta el manejador de señales.

Para algunas de las señales, la implementación puede llamar std :: signal ( sig, SIG_IGN ) al inicio del programa. Para el resto, la implementación debe llamar std :: signal ( sig, SIG_DFL ) .

(Nota: POSIX introdujo sigaction para estandarizar estos comportamientos definidos por la implementación)

Contenidos

Parámetros

sig - la señal para establecer el manejador de señales. Puede ser un valor definido por la implementación o uno de los siguientes valores:
define tipos de señal
(constante macro)
handler - el manejador de señales. Debe ser uno de los siguientes:
  • SIG_DFL macro. El manejador de señales se establece al manejador de señales predeterminado.
  • SIG_IGN macro. La señal es ignorada.
  • Un puntero a una función. La firma de la función debe ser equivalente a la siguiente:
extern "C" void fun ( int sig ) ;


Valor de retorno

Manejador de señal anterior en caso de éxito o SIG_ERR en caso de fallo (establecer un manejador de señales puede estar deshabilitado en algunas implementaciones).

Manejador de señales

Las siguientes limitaciones se imponen a la función definida por el usuario que se instala como un manejador de señales.

Si el manejador de señales es llamado NO como resultado de std::abort o std::raise (señal asíncrona), el comportamiento es indefinido si

  • el manejador de señales llama a cualquier función dentro de la biblioteca estándar, excepto
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal con el primer argumento siendo el número de la señal manejada actualmente (el manejador asíncrono puede volver a registrarse a sí mismo, pero no otras señales).
  • el manejador de señales hace referencia a cualquier objeto con duración de almacenamiento estático que no sea std::atomic o (desde C++11) volatile std:: sig_atomic_t .
(hasta C++17)

Una operación atómica simple sin bloqueo es una invocación de una función f desde <atomic> o <stdatomic.h> (desde C++23) , tal que:

El comportamiento es indefinido si cualquier manejador de señales realiza cualquiera de las siguientes acciones:

  • llamada a cualquier función de biblioteca, excepto operaciones atómicas simples sin bloqueo y las siguientes funciones seguras para señales (nota, en particular, la asignación dinámica no es segura para señales):
  • acceso a un objeto con duración de almacenamiento de hilo
  • una expresión dynamic_cast
  • una expresión throw
  • entrada a un try block
  • inicialización de una variable estática que realiza inicialización dinámica no local (incluyendo retrasada hasta el primer uso ODR)
  • espera por la completación de la inicialización de cualquier variable con duración de almacenamiento estático debido a que otro hilo la está inicializando concurrentemente
(desde C++17)

Si la función definida por el usuario retorna al manejar SIGFPE , SIGILL , SIGSEGV o cualquier otra señal definida por la implementación que especifique una excepción computacional, el comportamiento es indefinido.

Si el manejador de señales es llamado como resultado de std::abort o std::raise (señal síncrona), el comportamiento es indefinido si el manejador de señales llama a std::raise .

Al entrar al manejador de señales, el estado del entorno de punto flotante y los valores de todos los objetos no están especificados, excepto para

(desde C++11)

Al retornar de un manejador de señales, el valor de cualquier objeto modificado por el manejador de señales que no sea volatile std:: sig_atomic_t o atómico sin bloqueo std::atomic es indeterminado.

(hasta C++14)

Una llamada a la función signal() se sincroniza con cualquier invocación resultante del manejador de señales.

Si un manejador de señales se ejecuta como resultado de una llamada a std::raise (sincrónicamente), entonces la ejecución del manejador está secuenciada después de la invocación de std::raise y secuenciada antes del retorno de la misma y se ejecuta en el mismo hilo que std::raise . La ejecución de los manejadores para otras señales está no secuenciada con respecto al resto del programa y se ejecuta en un hilo no especificado.

Dos accesos al mismo objeto de tipo volatile std:: sig_atomic_t no resultan en una carrera de datos si ambos ocurren en el mismo hilo, incluso si uno o más ocurren en un manejador de señales. Para cada invocación del manejador de señales, las evaluaciones realizadas por el hilo que invoca un manejador de señales pueden dividirse en dos grupos A y B, de modo que ninguna evaluación en B ocurre antes de las evaluaciones en A, y las evaluaciones de dichos volatile std:: sig_atomic_t toman valores como si todas las evaluaciones en A ocurrieran antes de la ejecución del manejador de señales y la ejecución del manejador de señales ocurriera antes de todas las evaluaciones en B.

(desde C++14)

Notas

POSIX requiere que signal sea seguro para hilos, y especifica una lista de funciones de biblioteca async-signal-safe que pueden ser llamadas desde cualquier manejador de señales.

Se espera que los manejadores de señales tengan vinculación C y, en general, solo utilicen las características del subconjunto común de C y C++. Sin embargo, las implementaciones comunes permiten utilizar una función con vinculación C++ como manejador de señales.

Ejemplo

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

Salida posible:

SignalValue: 0
Sending signal: 2
SignalValue: 2

Referencias

  • Estándar C++23 (ISO/IEC 14882:2024):
  • 17.13.5 Manejadores de señales [support.signal]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 17.13.5 Manejadores de señales [support.signal]
  • Estándar C++17 (ISO/IEC 14882:2017):
  • 21.10.4 Manejadores de señal [support.signal]

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 3756 C++17 no estaba claro si std::atomic_flag es seguro para señales lo es

Véase también

ejecuta el manejador de señal para una señal particular
(función)
barrera entre un hilo y un manejador de señal ejecutado en el mismo hilo
(función)
Documentación C para signal