2017-03-01 1 views
1

Donc j'écris un shell UNIX pour une classe de la mienne et en gros je prends un argument, si l'argument a '&' à la fin de celui-ci alors j'ai besoin du processus parent pour invoquer attendez();.J'ai des problèmes avec forking un processus

Mon problème ici est que le programme doit accepter les entrées jusqu'à ce que je tape exit, donc tout est dans une boucle 'while'. Les choses tournent parfaitement jusqu'à ce que j'appelle une commande avec '&' à la fin, et puis je peux voir que le processus parent se termine, puis l'enfant se termine, mais alors je ne suis pas à mon invite normale pour accepter une entrée qui est "osh>".

Donc, fondamentalement, voici ma sortie normale lorsque je lance une commande simple:

osh> ls -l 
child:0 
a.out main main.cpp main.cpp~ 
parent: 8695 

Mais quand je lance une commande avec le « & » à la fin ce qui se passe:

osh> ls -l & 
parent: 27082 
osh> child:0 
total 44 
-rwxr-xr-x 1 myuser users 10368 Mar 1 14:46 a.out 
-rwxr-xr-x 1 myuser users 23368 Mar 1 14:00 main 
-rw-r--r-- 1 myuser users 1658 Mar 1 14:46 main.cpp 
-rw-r--r-- 1 myuser users 1676 Mar 1 14:45 main.cpp~ 
<cursor is here accepting commands, but no osh> prompt> 

Si quelqu'un a des commentaires ou des suggestions, serait apprécié. J'ai l'impression que c'est juste un petit bogue, mais j'ai traversé un débogueur plusieurs fois et je ne trouve rien. Je n'ai tout simplement pas beaucoup d'expérience à faire des choses. Voici le code complet à regarder:

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

#define MAX_LINE 80 //the maximum length command 

using namespace std; 

int main() 
{ 
    char* args[MAX_LINE/2 + 1]; //command line arguments 
    char str[41]; //intitialize string for input 
    int should_run = 1; //flag to determine when to exit program 
    bool status; //status of whether or not an ampersand is in the passed argument 

    while (should_run) { 
    int index = 0; 

    cout << "osh> "; 
    fflush(stdout); 

    cin.getline(str, 41); 

    args[index] = strtok(str, " "); 

    while (args[index] != NULL) { 
     index++; 
     args[index] = strtok(NULL, " "); 
    } 

    if (strcmp (args[0], "exit") == 0) //in input is "exit", exit the while loop 
     break; 

    if (*args[index - 1] == '&') //check whether to run processes concurrently 
     status = true; 

    args[index - 1] = NULL; //remove & to make sure arguments are valid 

    // (1) fork a child process using fork() 
    pid_t pid = fork(); 

    if (pid < 0) { //error handling 
     perror("Fork Failed."); 
     break; 
     } 
    // (2) the child process will invoke execvp() 
    if (pid == 0) { 
     //child process 
     cout << "child:" << pid << endl; 
     if (execvp (args[0], args) == -1) { 
     perror ("exec"); 
     } 
    } 

    // (3) if command didn't included &, parent will invoke wait() 
    //parent process 
    if (pid > 0) { 
     // parent process 
     if (!status) { 
     wait(0); 
     } 
     cout << "parent: " << pid << endl; 
    } 
    } 

    return 0; 
} 

Edit: Aussi juste réalisé que ma deuxième sortie I posté, il montre « osh> » une deuxième fois après le processus parent, ne sais pas comment décrire cette erreur.

+0

C'est à peu près comme cela fonctionne dans tous les autres shell Unix. – immibis

+0

Une raison de ne pas écrire cela en C, ce qui est presque tout? –

+0

@NeilButterworth Juste plus à l'aise avec C++ – HOAX

Répondre

3

Non, vous êtes déjà à l'invite de commande:

osh> child:0 
total 44 

C'est votre commande, l'invite, l'invite osh>.

Votre problème ici est que votre ordinateur fait exactement ce que vous lui dites de faire, et non ce que vous vouliez qu'il fasse. Votre code (qui a un bug majeur non lié, auquel je vais arriver dans le moment) dit de ne pas attendre que le processus fils finisse, et continue, si & a été entré.

Et c'est exactement ce qui s'est passé. Le processus enfant a démarré et votre processus parent a immédiatement émis l'invite osh> suivante. Et, il l'a fait si vite, avant même que le processus enfant n'obtienne un changement pour produire n'importe quelle sortie. En tant que tel, la sortie du processus enfant apparaît sur votre terminal, après l'invite osh>. Puisque votre processus parent a déjà produit son invite, il attend maintenant votre prochaine entrée, et il n'a aucune raison de ne pas continuer à attendre, une fois que le processus enfant s'est terminé, et a fini de produire sa sortie.

Cela répond à la question de savoir ce qui est arrivé à votre invite. Vous n'avez pas expliqué ce que vous attendiez, donc rien de plus ne peut être dit à ce sujet; mais si vous souhaitez réémettre l'invite à nouveau, après que le processus enfant se termine, vous pouvez le faire en traitant correctement le signal SIGCHLD. Voir votre livre C++ pour plus d'informations.

En ce qui concerne votre bogue sans rapport, il est en fait deux bugs:

if (*args[index - 1] == '&') 
    status = true; 

args[index - 1] = NULL; //re 

Premier bug: tout ce qui commence par '&', et non pas seulement « & » par lui-même, va déclencher le comportement de travail de fond.

Deuxième bogue: si le code '&' n'a pas été entré, ce code coupe toujours le dernier mot entré. C'est pourquoi, lorsque vous avez entré la commande ls -l, vous avez fini par exécuter ls et obtenir la sortie résultante à partir de votre première commande.

+0

Merci pour la longue réponse, se penchera sur mes erreurs. – HOAX

+0

Notez que dans le shell POSIX (Bash, Korn, ...), un '&' marque la fin d'une commande sauf si elle est suivie d'une autre '&&' (bien, cela marque toujours la fin de la commande - c'est un terminateur différent , cependant) - ou à moins que ce soit une des syntaxes obscures [Bash redirection] (https://www.gnu.org/software/bash/manual/bash.html#Redirections) qui utilise '&' comme premier caractère (' &> 'et parents). –

+0

Hey Sam, serais-je capable d'utiliser waitpid au lieu de gérer le SIGCHLD directement? Avoir du mal à comprendre ce concept – HOAX