2016-11-14 2 views
0

J'essaye d'écrire un programme en C qui crée 2 processus fils avec chacun d'entre eux en exécutant un execvp.Problème de tuyauterie: le premier enfant écrit trop dans le tuyau

Mon problème est que le premier enfant écrit trop de données dans le tuyau à partir duquel l'autre enfant lit.

int main(int argc, char* argv[]){ 

//unnamed pipe 
int pipeFd[2], statusFirst,statusSecond; 
pid_t childPidOne,childPidTwo; 

if(pipe(pipeFd) < 0){ 
    perror("Pipe error:\n"); 
    exit(EXIT_FAILURE); 
} 

switch(childPidOne = fork()){ 
    case -1: 
     perror("First Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("First child\n"); 
     close(pipeFd[1]); 
     if((execvp(argv[1], &argv[1])) < 0){ 
      perror("First execvp error:\n"); 
     } 
     printf("End First cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 

switch(childPidTwo = fork()){ 
    case -1: 
     perror("Second Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("Second cild\n"); 
     close(pipeFd[0]); 
     if((execvp(argv[3], &argv[3])) < 0){ 
      perror("Second execvp error:\n"); 
     } 
     printf("End Second cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 


close(pipeFd[0]); 
close(pipeFd[1]); 


if((waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0){ 
    perror("First waitpid error:\n"); 
}else{ 
    if (WIFEXITED(statusFirst)) { 
     printf("First exited, status=%d\n", WEXITSTATUS(statusFirst)); 
    } else if (WIFSIGNALED(statusFirst)) { 
     printf("First killed by signal %d\n", WTERMSIG(statusFirst)); 
    } else if (WIFSTOPPED(statusFirst)) { 
     printf("First stopped by signal %d\n", WSTOPSIG(statusFirst)); 
    } else if (WIFCONTINUED(statusFirst)) { 
     printf("First continued\n"); 
    } 
} 


if((waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0){ 
    perror("Second waitpid error:\n"); 
} 
if (WIFEXITED(statusSecond)) { 
    printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond)); 
    } else if (WIFSIGNALED(statusSecond)) { 
    printf("Second killed by signal %d\n", WTERMSIG(statusSecond)); 
    } else if (WIFSTOPPED(statusSecond)) { 
    printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond)); 
    } else if (WIFCONTINUED(statusSecond)) { 
     printf("Second continued\n"); 
     } 

    exit(0); 
return 0; 
    } 

Peut-être que j'ai une mauvaise compréhension de la façon dont conduite + travail fourchette + de execvp alors laissez-moi vous dire ce que je fais dans mon code:

  1. Je crée un tuyau sans nom - les deux Childs utilisent le même tuyau
  2. Je vais créer deux Childs par bifurquer les
  3. Depuis que j'exécute mon programme comme celui-ci: ./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL] ou tout simplement pour vous donner un exemple: je ./pipeline echo Hello | wc -m fermer le site de lecture de la conduite
  4. Et puis appelez execvp(argv[1], &argv[1])

Et c'est là l'erreur se produit (je suppose): Je ne ferme du côté de l'écriture jusqu'à ce que le deuxième enfant ne cause execvp ne sera jamais revenir si elle réussit.

Et je sais que execvp ne ferme pas les descripteurs de fichier ouverts (il peut être fermé en utilisant un drapeau dans fcntl comme mentionné dans What does the FD_CLOEXEC flag do?).

Exemple

Laissez-moi vous donner un exemple.

echo Hello | wc -m 

sort le résultat

Parce que l'appel système wc (nombre de mots) compte les caractères (-m) dans une donnée String

C'est exact parce que bonjour = 5 + 1 (qui est \n ou \0 je suppose) et cela fait 6.

Maintenant, en cours d'exécution de mon programme donne le résultat

Ou pour obtenir plus d'informations

echo hello | wc 

sorties

1 (ligne) 1 (mot) 6 (caractères)

Et ./pipeline echo hello | wc

sorties

3 (lignes) 9 (mot) 56 (caractères)

J'ai cherché pendant des jours mais je ne peux pas comprendre en dehors.

Des idées?

Merci beaucoup!

+1

Si vous utilisez './pipeline echo hello | wc' pour exécuter votre programme, alors il ne fait pas ce que vous pensez qu'il est. Votre programme voit 'argv [1] == echo',' [2] == hello' et _nothing else_. La sortie (combinée) de votre programme est ensuite redirigée vers wc. Pour (complètement) réaliser ce que je pense que vous voulez faire, vous devez échapper le caractère de pipe et le détecter dans votre code (ainsi vous savez quelles parties de la ligne de commande pour passer dans chaque processus d'enfant). – TripeHound

+0

@TripeHound, j'ai échappé le caractère manuellement en tapant ./pipeline echo hello \ | wc et cela a fonctionné pour moi, sauf le fait que le second enfant démarre wc en mode interactif (attend l'entrée et ctrl + d pour marquer la fin de l'entrée). Cela me donne le résultat correct de 1 1 6. Cela signifie que l'entrée du premier enfant est ignorée. Des idées ? –

Répondre

0

Résolu moi-même.

Oublié d'utiliser dup2.

Il suffit de taper la commande dup2 après la commande close et tout ira bien.