2010-09-23 19 views
5

He estado tratando de averiguar si esto es posible de la manera en que lo he hecho o no. Este programa debe bifurcar un proceso secundario que enruta la impresión a STDOUT, y el padre debe salir para devolver la solicitud de la terminal. El niño debería esperar que SIGINT le diga cuándo cerrar. Sin embargo, recuerdo haber leído que SIGINT solo se envía a procesos en primer plano, lo que explica por qué mi hijo abandonado no se ve afectado por CTRL + C. ¿Hay alguna forma de conseguir que el niño abandonado reciba una señal enviada desde la terminal, o alguna llamada al sistema en la terminal para llevarlo al primer plano donde pueda recibir SIGINT? ¿O mi búsqueda es desesperada?Problema al enviar la señal al proceso secundario en C

Código:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <sys/wait.h> 
#include <sys/types.h> 

/* signal handler for the child process */ 
void catchInt (int signum) 
{ 
printf("\nMy sincerest apologies, master\n"); 
    exit(0); 
} 

/* signal handler for the parent process */ 
void ignoreInt (int signum) 
{ 
/* prevent any extra output from being printed */ 
fflush(stdout); 
/* wait for child to apologize before replying */ 
wait(NULL); 
printf("You're welcome\n"); 
exit(0); 
} 

/* signal handler for the child's alarm */ 
void catchAlarm (int signum) 
{ 
printf("It's great to be alive\n"); 
/* reset the alarm */ 
signal(SIGALRM, catchAlarm); 
alarm(3); 
} 

int main() { 

pid_t pid; 

/* fork process */ 
pid = fork(); 
if (pid < 0) /* error handler */ 
{ 
    fprintf(stderr, "Fork Failed"); 
    exit(-1); 
} 

/* child */ 
else if (pid == 0) 
{ 
    printf("It's great to be alive\n"); 
    /* catch SIGINT and handle as the child should */ 
    signal(SIGINT, catchInt); 
    /* catch SIGALRM being sent by alarm() */ 
    signal(SIGALRM, catchAlarm); 
    /* set alarm for 3 seconds */ 
    alarm(3); 
    for (;;) 
    { 
    printf("I have 42001 children and not one comes to visit\n"); 
    usleep(500000); 
    } 
} 

/* parent */ 
else 
{ 
    /* exit to abandon child process in the background */ 
    exit(0); 
} 

return(0); 
} 

Respuesta

2

Si desea que su hijo reciba SIGINT cuando se toca el carácter de interrupción en el terminal de control, debe estar en el grupo de proceso en primer plano. Esto se puede conseguir:

int ctty = open("/dev/tty", O_RDONLY); 
while (tcgetpgrp(ctty) == getpgrp()) 
    usleep(100000); 
setpgid(0, tcgetpgrp(ctty)); 
close(ctty); 

(Hay que esperar hasta que la cáscara cambia el grupo de procesos en primer plano después de las salidas de los padres, sin embargo - no estoy seguro de una mejor forma de hacerlo que dando vueltas en un bucle, . como en el ejemplo aceptan sugerencias ...)


PS: Tenga en cuenta que el grupo de procesos en primer plano se puede cambiar en cualquier momento - por ejemplo, cuando otro proceso se ejecuta desde la cáscara. No estoy seguro de cuál es tu objetivo final, pero tal vez haya una mejor manera de hacerlo, sea lo que sea.

+0

¡Esto realmente funciona a la perfección! Tendré que buscar más grupos de procesos. ¡Gracias! – JKomusin

+0

@JKomusin: aunque no es realmente una solución perfectamente robusta, consulte la actualización. – caf

1

Usted puede utilizar el comando kill para enviar una señal a un número de proceso se especifica:

kill -2 12345 

Por supuesto, ayuda si su código identifica el PID para matar (el niño debe informar su PID cuando comienza a circular). Pero con solo cambios triviales (como omitir la función ignoreInt() no utilizada e informar el PID del proceso hijo), funcionó bien tal como está escrito, y el comando kill también funcionó.

código comprimido:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <signal.h> 

static void catchInt(int signum) 
{ 
    printf("\nMy sincerest apologies, master (%d)\n", signum); 
    exit(0); 
} 

static void catchAlarm(int signum) 
{ 
    printf("It's great to be alive (%d)\n", signum); 
    signal(SIGALRM, catchAlarm); 
    alarm(3); 
} 

int main(void) 
{ 
    pid_t pid = fork(); 

    if (pid < 0) 
    { 
     fprintf(stderr, "Fork Failed"); 
     exit(-1); 
    } 
    else if (pid == 0) 
    { 
     printf("It's great to be alive (%d)\n", (int)getpid()); 
     signal(SIGINT, catchInt); 
     signal(SIGALRM, catchAlarm); 
     alarm(3); 
     for (;;) 
     { 
      printf("I have 42001 children and not one comes to visit\n"); 
      usleep(500000); 
     } 
    } 
    return(0); 
} 

Si va a incluir <sys/types.h>, se debe normalmente ser el primero de los encabezados de POSIX (y por lo tanto antes de <unistd.h>). El hecho de que aparezca en último lugar sugiere que no debería necesitarlo en absoluto, pero parece recordar una pregunta anterior en la que afirmó que era necesaria. (Otoh, no hay una llamada a cualquiera de la familia wait(), por lo <sys/wait.h> es innecesaria, y estoy convencido de que moderadamente <sys/types.h> no es necesario en la mayoría de los sistemas modernos.)

+0

Jaja, estoy casi seguro de que mi disquete de netbook de Ubuntu es la fuente de mis problemas sys/types.h, sin ello no se declara pid_t para mí. Pero faltan otros encabezados en mi sistema, por lo que no es impactante.El motivo de los encabezados excesivos es que creo que acabo de copiar todos mis encabezados rápidamente cuando hice esto y aún no he recortado la grasa. Gracias por la respuesta, matar funciona bastante bien para mis propósitos atm. – JKomusin

0

No, la señal SIGINT sólo se envía al primer plano procesa cuando se acciona mediante el uso de CTRLC (o lo que sea stty tiene la pulsación intr establecer a).

Siempre puede enviar un SIGINT a un proceso específico con kill -INT 99999 (donde 99999 es el ID del proceso).

+0

Gracias, mata -INT tendrá que hacer por ahora. – JKomusin

Cuestiones relacionadas