2010-09-23 2 views
5

Ho cercato di capire se questo è possibile nel modo in cui l'ho fatto o no. Questo programma dovrebbe eseguire il fork di un processo figlio che esegue il looping della stampa su STDOUT e il genitore dovrebbe uscire per restituire il prompt del terminale. Il bambino dovrebbe quindi attendere che SIGINT dica quando chiudere. Tuttavia ricordo di aver letto che SIGINT è inviato solo ai processi in primo piano, il che spiega perché il mio bambino abbandonato non è influenzato da CTRL + C. Esiste un modo per far sì che il bambino abbandonato possa ricevere un segnale inviato dal terminale o qualche chiamata di sistema nel terminale per portarlo in primo piano dove può ricevere SIGINT? O la mia ricerca è senza speranza?Problemi durante l'invio del segnale al processo figlio in C

Codice:

#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); 
} 

risposta

2

Se si desidera che il bambino riceva SIGINT quando il carattere di interruzione viene colpito sul terminale di controllo, deve trovarsi nel gruppo di processi in primo piano. È possibile raggiungere questo obiettivo:

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

(Dovete aspettare fino a quando il guscio cambia il gruppo di processi in primo piano dopo le vostre uscite genitore, anche se - non sono sicuro di un modo migliore per farlo che gira in un loop, . come nell'esempio Suggerimenti accolgono ...)


PS: Essere consapevoli del fatto che il gruppo di processo di primo piano può cambiare in qualsiasi momento - per esempio, quando un altro processo viene eseguito dalla shell. Non sono sicuro di quale sia il tuo obiettivo finale, ma forse c'è un modo migliore per farlo, qualunque esso sia.

+0

In realtà funziona perfettamente! Dovrò esaminare di più i gruppi di processi. Grazie! – JKomusin

+0

@ JKomusin: Non è davvero una soluzione perfettamente robusta, vedi aggiornamento. – caf

1

È possibile utilizzare il comando kill per inviare un segnale ad un numero di processo specificato:

kill -2 12345 

Naturalmente, è utile se il codice identifica quale PID per uccidere (il bambino dovrebbe segnalare il suo PID quando inizia il ciclo). Ma con solo modifiche banali (come omettendo la funzione ignoreInt inutilizzato(), e reporting PID del processo figlio), ha funzionato bene come scritto - e il comando kill ha lavorato su di esso troppo.

codice compressa:

#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); 
} 

Se avete intenzione di includere <sys/types.h>, dovrebbe normalmente essere il primo delle intestazioni POSIX (e quindi prima <unistd.h>). Il fatto che sia elencato per ultimo suggerisce che non dovresti averne bisogno - ma mi sembra di ricordare una domanda precedente in cui affermavi che era necessario. (OTOH, non c'è nessuna chiamata a uno dei wait() famiglia, in modo <sys/wait.h> è inutile, e io sono moderatamente convinto che <sys/types.h> non è necessaria nella maggior parte dei sistemi moderni.)

+0

Haha, sono quasi sicuro che il mio netbook distro di Ubuntu è la fonte dei miei problemi sys/types.h, senza che pid_t non sia dichiarato per me. Ma nel mio sistema mancano altri header di questo tipo, quindi non è scioccante.La ragione per le intestazioni eccessive è che ho appena copiato tutte le mie intestazioni velocemente quando ho fatto questo e non ho ancora tagliato il grasso. Grazie per la risposta, uccidere funziona abbastanza bene per i miei scopi. – JKomusin

0

No, il segnale SIGINT viene inviato solo al primo piano elabora quando è azionato utilizzando CTRLC (o qualsiasi altra cosa stty ha la intr sequenza di tasti impostata).

È sempre possibile inviare un SIGINT a un processo specifico con kill -INT 99999 (dove 99999 è l'ID di processo).

+0

Grazie, kill -INT dovrà fare per ora. – JKomusin