2011-01-28 10 views
6

¿Hay alguna diferencia entre "código listado 1" y "código listado 2"? Debido a que en el Listado de Código 1, el proceso secundario es capaz de atrapar la señal SIGTERM y salir muy bien. Pero la lista de códigos 2 está terminando abruptamente en la señal SIGTERM.señal de llamada después de la horquilla

estoy usando Linux y C.

Listado de Código 1

if (signal(SIGTERM, stopChild) == SIG_ERR) { 
    printf("Could not attach signal handler\n"); 
    return EXIT_FAILURE; 
} 
pid = fork(); 

Listado de Código 2

pid = fork(); 
if (signal(SIGTERM, stopChild) == SIG_ERR) { 
    printf("Could not attach signal handler\n"); 
    return EXIT_FAILURE; 
} 

La parte extraña es que en Listado de Código 2, los procesos hijo y principal configuran el controlador de señal para SIGTERM. Entonces, se supone que esto debe funcionar. ¿No es así?

+0

Lo acabo de probar, funciona bien para mí. Ambos procesos salen graciosamente a través de la llamada a stopChild() en ambos casos. –

+0

¿Está por casualidad llamando a fork() desde dentro de un hilo? –

+2

¿Puede proporcionar un programa de ejemplo completo que muestre el comportamiento? – wich

Respuesta

5

Si envía el SIGTERM de la matriz, el resultado final depende del orden en que se programen los procesos.

Si el niño se programó en primer lugar, todo funciona:

           +---------------+ 
               | pid = fork(); | 
               +-------+-------+ 
        parent        |        child 
          +-----------------------------+-----------------------------+ 
          |               | 
          |         +-------------------------+--------------------------+ 
          |         | if (signal(SIGTERM, stopChild) == SIG_ERR) {  | 
          |         |  printf("Could not attach signal handler\n"); | 
          |         |  return EXIT_FAILURE;       | 
          |         | }             | 
          |         +-------------------------+--------------------------+ 
          |               | 
          .               . 
          .               . 
          .               . 
          |               | 
+-------------------------+--------------------------+        | 
| if (signal(SIGTERM, stopChild) == SIG_ERR) {  |        | 
|  printf("Could not attach signal handler\n"); |        | 
|  return EXIT_FAILURE;       |        | 
| }             |        | 
+-------------------------+--------------------------+        | 
          |               | 
          |               | 
          |               | 
      +-------------+-------------+            | 
      | if (pid > 0) {   |            | 
      |  kill(pid, SIGTERM); |            | 
      | }       |            | 
      +-------------+-------------+            | 
          |               | 
          |               | 
          |               | 

Pero si el paren se programó en primer lugar, el niño puede no haber tenido tiempo para configurar el controlador de señal:

           +---------------+ 
               | pid = fork(); | 
               +-------+-------+ 
        parent        |        child 
          +-----------------------------+-----------------------------+ 
          |               | 
+-------------------------+--------------------------+        | 
| if (signal(SIGTERM, stopChild) == SIG_ERR) {  |        | 
|  printf("Could not attach signal handler\n"); |        | 
|  return EXIT_FAILURE;       |        | 
| }             |        | 
+-------------------------+--------------------------+        | 
          |               | 
          |               | 
          |               | 
      +-------------+-------------+            | 
      | if (pid > 0) {   |            | 
      |  kill(pid, SIGTERM); |            | 
      | }       |            | 
      +-------------+-------------+            | 
          |               | 
          .               . 
          .               . 
          .               . 
          |               | 
          |         +-------------------------+--------------------------+ 
          |         | if (signal(SIGTERM, stopChild) == SIG_ERR) {  | 
          |         |  printf("Could not attach signal handler\n"); | 
          |         |  return EXIT_FAILURE;       | 
          |         | }             | 
          |         +-------------------------+--------------------------+ 
          |               | 
          |               | 
          |               | 

Este se llama raza condición, porque el resultado final depende de quién se ejecuta primero.

+0

No creo que este fue el problema porque el proceso principal se durmió 10 segundos antes de que envíe la señal. De todos modos, estoy aceptando esto como la respuesta ahora, ya que no puedo reproducir el problema. – Sabya

0

Pues bien, según el hombre tenedor:

El tenedor(), fork1(), y forkall() Funciones de crear un nuevo proceso. El espacio de direcciones del nuevo proceso (proceso secundario) es una copia exacta del espacio de direcciones del proceso de llamada (proceso principal). El proceso hijo hereda los atributos siguientes del proceso principal:

...

los valores de manejo o la señal (es decir, SIG_DFL, SIG_IGN, SIG_HOLD, dirección de función)

En el primer ejemplo el controlador de señal se copiará desde el contexto del padre al hijo bifurcado. Pero no puedo explicar por qué en el segundo ejemplo de configuración, el controlador de señal en el niño fallaría.

+1

Pero en el segundo ejemplo se usa la señal() para ambos procesos. Por lo tanto, también debe establecer el manejador de señal para el proceso secundario, ¿no es así? –

+0

@Sergey, ¡exactamente esa es mi duda! – Sabya

+0

POSIX dice que las señales _pending_ para el elemento primario no se envían al elemento secundario, sino que comienza con un conjunto de señales inicializado a cero. Pero, el niño _debería heredar a los controladores. Llamar a tenedor() dentro de un hilo en ausencia de pthread_atfork() podría explicar lo que está experimentando el OP, sin embargo. –

3

En primer lugar, signal() está en desuso, es mejor usar sigaction(). No creo que fork() esté en peligro de desaparecer del todo, ya que muchas cosas lo usan, pero sigaction() proporciona una interfaz mucho más agradable.

El comportamiento que está experimentando normalmente se produce llamando al tenedor() desde dentro de un subproceso. POSIX aborda esta specifically:

Un proceso se crea con un solo hilo . Si un proceso multiproceso de llama fork(), el nuevo proceso contendrá una réplica de la cadena de llamada y su espacio de direcciones completo, incluyendo posiblemente los estados de mutexes y otros recursos. En consecuencia, para evitar errores, el proceso hijo solo puede ejecutar operaciones async-signal-safe hasta en el momento en que se llame a una de las funciones de exec. [THR] Los manipuladores de horquillas pueden establecerse por medio de la función pthread_atfork() para mantener invariantes de aplicación a través de llamadas fork().

Cuando el tenedor llamadas de aplicación() desde un manejador de señal y cualquiera de los tenedor manipuladores registrados por pthread_atfork() llama a una función que no está desincronizado-señal segura, el comportamiento es indefinido.

Esto significa que, en lugar de heredar una copia de todo el espacio de direcciones de los padres, que heredan sólo una copia de las llamadas roscas espacio de direcciones, que no contiene los controladores. Podría ser concebible que estés, de hecho (quizás incluso inconscientemente) llamando fork() desde dentro de un hilo.

Un proceso secundario obtiene una copia del espacio de direcciones del padre. La única diferencia con las señales sería pendientes de las señales, que el niño no recibirá ya que recibe un conjunto de señales inicializado a cero. Pero sí, sí recibe una copia de los controladores.

+0

señal de llamada antes de que el tenedor sea realmente exitoso, por lo que las disposiciones de señal se copian al niño, llamándolo después de que el tenedor es el caso que se rompe, es decir, de alguna manera la señal de llamada en el niño no funciona. – wich

+0

@wich - por eso sospecho mucho de que fork() se llame en un hilo. –

Cuestiones relacionadas