2016-02-09 1 views
1

J'essaie de créer un programme qui imite un shell Linux.Comment puis-je terminer le programme lorsque je n'attends pas le processus fils dans le parent?

Et il fonctionne en deux modes

(1) Mode interactif (Aucun) arguments

Attendez que le processus enfant. Exécute une commande à la fois.

(2) mode batch (Un fichier donné)

Ne pas attendre. Essayez d'exécuter les commandes en parallèle. Mon code est assez long donc j'ai décidé de faire un exemple de programme pour adresser (focus) sur le problème que je suis confronté.

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

struct commands 
{ 
    char *cmd[2]; 
}; 

int main(int argc, char *argv[]) 
{ 
    printf("A program made to understand execvp\n"); 

    commands threeCommands[3]; 

    pid_t process; 
    int child_status; 

    threeCommands[0].cmd[0] = "date"; 
    threeCommands[0].cmd[1] = NULL; 

    threeCommands[1].cmd[0] = "pwd"; 
    threeCommands[1].cmd[1] = NULL; 

    threeCommands[2].cmd[0] = "cal"; 
    threeCommands[2].cmd[1] = NULL; 

    for(int i = 0;i <3;i++) 
    { 
     process = fork(); 

     if(process == 0) 
     { 
      execvp(threeCommands[i].cmd[0],threeCommands[i].cmd); 
     } 
     else 
     { 
      //wait(&child_status); 
     } 
    } 

    return 0; 
} 

Comme vous pouvez le voir, je suis Décommenter l'attente pour que j'essaie de faire le traitement simultané et les résultats des commandes sont répartis au hasard et peut-être entremêlées.

Le problème est après l'exécution des trois commandes date,pwd,cal

Le programme ne se termine pas. Il gèle dans cet état et ne se termine pas simplement, donc mon curseur est là comme s'il avait besoin d'une entrée. Et mon programme ne se termine pas. Comment puis-je réparer cela?

Dois-je tuer ou quoi?

Répondre

0

Vous devez appeler le wait pour que les processus enfants se terminent proprement. Vous n'avez pas besoin d'appeler le wait immédiatement, mais vous devez appeler le wait avant la fin du programme sinon vous avez des processus enfant zombie. Cela fonctionne pour moi et fonctionne encore tous les programmes en parallèle:

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

struct commands 
{ 
    char *cmd[2]; 
}; 

int main(int argc, char *argv[]) 
{ 
    printf("A program made to understand execvp\n"); 

    struct commands threeCommands[3]; 

    pid_t process; 
    int child_status; 

    threeCommands[0].cmd[0] = "date"; 
    threeCommands[0].cmd[1] = NULL; 

    threeCommands[1].cmd[0] = "pwd"; 
    threeCommands[1].cmd[1] = NULL; 

    threeCommands[2].cmd[0] = "cal"; 
    threeCommands[2].cmd[1] = NULL; 

    for(int i = 0;i <3;i++) 
    { 
     process = fork(); 

     if(process == 0) 
     { 
      execvp(threeCommands[i].cmd[0],threeCommands[i].cmd); 
     } 
    } 

    for(int i = 0;i <3;i++) 
    { 
     wait(&child_status); 
    } 

    return 0; 
} 

L'autre option est d'ignorer le signal SIGCHLD:

signal(SIGCHLD, SIG_IGN); // automatically reap child processes 
+0

En fait, on n'a pas * besoin * d'appeler 'wait' pour récolter les processus fils, même si c'est" de bonnes manières "de le faire. Si un processus fils devient orphelin (lorsque ses parents se terminent sans attendre que l'enfant sorte), le processus init (pid 1) prendra le relais en tant que parent.Un processus de zombie est un processus qui s'est terminé mais qui n'a pas été récolté oui (c'est-à-dire que le parent n'a pas appelé 'wait'). –

1

Appuyez simplement sur la touche Entrée après la sortie.

Si le processus parent se termine avant que l'enfant ne soit traité, le shell affichera l'invite après la sortie du processus parent, puis les processus fils afficheront leur sortie, mais le shell n'imprimera pas une nouvelle invite. Regardez quelques lignes au-dessus de la fin de la sortie pour voir l'invite après la sortie du processus parent.

Par exemple, après avoir modifié votre code pour ajouter un sleep(1) avant d'appeler execvp (pour forcer les processus enfants à retarder) Je reçois la sortie suivante sur mon système:

 
[~/tmp]$ ./a.out 
A program made to understand execvp 
[~/tmp]$ tis 9 feb 2016 18:54:06 CET 
/home/XXXX/tmp 
    Februari 2016  
sö må ti on to fr lö 
    1 2 3 4 5 6 
7 8 9 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29     

Comme vous le voyez l'invite est imprimé avant l'exécution de la commande date (.[~/tmp]$ avant la sortie). Appuyez sur Entrez pour ramener l'invite.

+0

C'est génial, mais comment entrer une clé d'entrée dans mon code? Donc je n'ai pas besoin de le faire manuellement – Pro

+0

@Pro Vous ne pouvez pas, parce que le processus parent n'existe plus. :) Ceci est un "problème" connu avec les processus enfants dans un programme démarré à partir du shell. –