¿Son std::signal y std::raise seguros para subprocesos?

7 minutos de lectura

avatar de usuario de xmllmx
xmllmx

Los estándares C y C++ admiten el concepto de señal. Sin embargo, el estándar C11 dice que la función signal() no se puede llamar en entornos de subprocesos múltiples, o el comportamiento no está definido. Pero creo que el mecanismo de la señal es por naturaleza para entornos de subprocesos múltiples.

Una cita del estándar C11 7.14.1.1.7

“El uso de esta función en un programa de subprocesos múltiples da como resultado un comportamiento indefinido. La implementación se comportará como si ninguna función de biblioteca llamara a la función de señal”.

¿Alguna explicación sobre esto?

El siguiente código es evidente.

#include <thread>
#include <csignal>

using namespace std;

void SignalHandler(int)
{
    // Which thread context here?
}

void f()
{
    //
    // Running in another thread context.
    //
    raise(SIGINT); // Is this call safe?
}

int main()
{
    //
    // Register the signal handler in main thread context.
    //
    signal(SIGINT, SignalHandler);

    thread(f).join();
}

  • La señalización se pensó originalmente para la comunicación entre procesos (IPC). En POSIX, la compatibilidad con señales en las aplicaciones de subprocesos múltiples fue en su mayoría una ocurrencia tardía, y muchas cosas de subprocesos se vuelven realmente malas en presencia de señales asíncronas.

    – nneonne

    30 de enero de 2013 a las 20:47

  • No está obligado a serlo, como dice la norma.

    –David Schwartz

    30 de enero de 2013 a las 20:49

  • Además, ¿por qué realmente necesitarías esto? Tiene formas mucho más sencillas de comunicarse dentro de una aplicación de subprocesos múltiples además de señalarse a sí mismo.

    – milimoose

    30 de enero de 2013 a las 20:55


  • Es estándar, me gustan las funciones estándar, si es que son mejores que las proporcionadas por el sistema.

    – xmllmx

    30 de enero de 2013 a las 20:58


  • @A.Mikhaylov ¿No es eso? exactamente ¿Qué dice la cita estándar en la pregunta del OP? Comportamiento indefinido significa que, por ejemplo, no sabe si un controlador de señal interrumpirá todos los subprocesos, o si se ejecutará en el corrientemente ejecución del subproceso, o en algún subproceso predecible como el que configuró el controlador. Si es lo último, ¿esto se adelanta a los otros subprocesos o espera su turno? Esto es solo la punta del iceberg cuando se trata de cosas que debe considerar para extender el comportamiento definido de esas funciones para subprocesos múltiples. El estándar C++ decidió ni siquiera intentarlo.

    – milimoose

    23 de julio de 2013 a las 14:24

Pero creo que el mecanismo de la señal es por naturaleza para entornos de subprocesos múltiples.

Creo que esta oración es el malentendido central. signal() es un método para inter-proceso comunicación, no para inter-hilo. Los subprocesos comparten memoria común y, por lo tanto, pueden comunicarse a través de mutexes y estructuras de control. Los procesos no tienen memoria común y deben arreglárselas con algunas estructuras de comunicación explícitas como signal() o el sistema de archivos.

  • Si un proceso registró un manejador de señales y otro proceso llamó aumento; ¿Puede el controlador de señal del primer proceso recibir la señal?

    – xmllmx

    30 de enero de 2013 a las 21:09

  • @xmllmx: Indefinido por el estándar. En Linux, sí. Sin embargo, cuando haga cosas específicas de Linux, simplemente use pthread.

    – titón

    30 de enero de 2013 a las 21:11

  • ¿Son estas funciones obsoletas e inútiles hoy? ¿Los estándares los admiten solo para compatibilidad con versiones anteriores?

    – xmllmx

    30 de enero de 2013 a las 21:14

  • @xmllmx: signal es reemplazado por sigaction, pero las funciones en sí mismas están perfectamente bien. Simplemente no están destinados a programas de subprocesos múltiples.

    – titón

    30 de enero de 2013 a las 21:16

  • Las señales @xmllmx tal como se definen en C no son particularmente útiles para nada. Requiere garantías definidas de implementación adicionales, como que ciertas funciones de biblioteca pueden llamarse en un controlador, para que sean útiles. Windows no admite mucho, en todo caso, más allá de lo que exige el estándar. En cambio, Windows tiene sus propios métodos específicos de plataforma para la comunicación entre procesos. Para la comunicación entre subprocesos, la biblioteca de subprocesos C++ 11 es compatible con Windows, por lo que puede escribir código compatible con el estándar portátil para la comunicación entre subprocesos.

    – bames53

    30 de enero de 2013 a las 21:53


Creo que está confundiendo la señalización, que es específica del proceso, con la comunicación entre subprocesos. Si lo que busca es compartir información entre subprocesos, probablemente encontrará lo que desea en el nuevo Biblioteca de soporte de subprocesos C ++ 11. Por supuesto, depende de lo que realmente quieras hacer.

Por lo que puedo decir de su código, desea que un hilo “señale” un evento de alguna manera y desea poder ejecutar algún código cuando se señala ese evento. Dado eso, echaría un vistazo más de cerca a la sección Futuros en la biblioteca de soporte de subprocesos.

  • Puedo entender y usar hilo, futuro, promesa, etc. Solo quiero saber por qué en lugar de cómo.

    – xmllmx

    30 de enero de 2013 a las 21:55

  • Me parece bien. Supongo que luego preguntaría, ¿qué quiere decir con seguro? ¿Está preguntando si se interrumpirán otros hilos? ¿Está preguntando si varios subprocesos pueden ingresar al controlador de señal?

    – Carlos

    30 de enero de 2013 a las 22:16

  • @xmllmx ¿Por qué? Porque esas son las herramientas destinadas a la tarea de hacer que los subprocesos cooperen, cuando signal() no es como el plano de documentación que te indica. Como en, nadie se molestó en definir las propiedades útiles que tendría para esta situación. (Así, se ejecutará un controlador de señal en el hilo que lo definió, o lo que sea). Estás preguntando por qué no deberías usar un martillo para cortar verduras en cubitos. Claro, si lo golpeas, terminarás con trozos más pequeños de vegetales, pero no es el enfoque que te gustaría tomar.

    – milimoose

    30 de enero de 2013 a las 23:56


  • @millimoose, +1 por tus explicaciones. Creo que esto se debe a que, en Windows, hay pocas personas que usen estas funciones.

    – xmllmx

    31 de enero de 2013 a las 9:09

  • @xmllmx MSDN también me dice soporte para <thread>, <mutex>y probablemente cualquier otro archivo de encabezado relacionado con esta característica de C++ sea nuevo en VS2012, por lo que también explicaría las cosas.

    – milimoose

    31 de enero de 2013 a las 13:33

La declaración del estándar C11 de que “El uso de esta función en un programa de subprocesos múltiples da como resultado un comportamiento indefinido”, se refiere específicamente a la función signal(). Entonces la pregunta es si el uso de signal() se realiza “en un programa de subprocesos múltiples”.

El término ‘programa de subprocesos múltiples’ no está definido en el estándar C por lo que puedo decir, pero lo interpretaría como un programa en el que se han creado múltiples subprocesos de ejecución y no se han completado. Eso significaría que en ese momento signal() se llama en su programa de ejemplo, el programa no tiene subprocesos múltiples y, por lo tanto, el comportamiento del programa no está indefinido según este requisito.

(Sin embargo, C ++ 11 requiere que “Todos los controladores de señal tengan enlace C”, [18.10 Other runtime support [support.runtime] p9]. Dado que su programa de ejemplo utiliza un controlador con enlace C++, el comportamiento no está definido).


Como otros han señalado, las señales no están destinadas a la comunicación entre subprocesos. Por ejemplo, los estándares C y C++ ni siquiera especifican en qué subproceso se ejecutan. En cambio, la biblioteca estándar proporciona otras herramientas para la comunicación entre subprocesos, como mutexes, atomics, etc.

Creo que simplemente malinterpretas el término. comportamiento indefinido, que desafortunadamente está muy sobrecargado para significar “sucederán cosas malas”. Aquí el término realmente solo significa lo que dice: el estándar C no hace ninguna suposición sobre lo que significa usar signal en un contexto de múltiples subprocesos.

En general, el signal/raise La interfaz en el estándar C no es muy útil por sí misma, sino solo un marcador de posición para las cosas específicas de la plataforma/SO que se definen encima.

Así que para una interacción entre signal y las amenazas no te dan un contrato. O dicho de otro modo, la interacción de signal y los hilos se dejan a la implementación de la plataforma.

¿Ha sido útil esta solución?