Travailler avec des tuyaux dans Unix C

J’ai de sérieux problèmes pour travailler avec des pipes en C. Je suis supposé prendre des arguments à partir de la ligne de commande (exemple: ./monprogramme 123 45 67), lire les arguments un caractère à la fois dans un tampon, envoyer le caractère à le processus enfant à compter, puis renvoyer le nombre total de caractères lus au processus parent. Mon code est le suivant (note: les commentaires sont ce que je suis censé faire):

// Characters from command line arguments are sent to child process // from parent process one at a time through pipe. // Child process counts number of characters sent through pipe. // Child process returns number of characters counted to parent process. // Parent process prints number of characters counted by child process. #include  #include  #include  #include  #include  static int toChild[2]; static int fromChild[2]; static char buffer; int main(int argc, char **argv) { int status; int nChars = 0; pid_t pid; pipe(toChild); pipe(fromChild); if ((pid = fork()) == -1) { printf("fork error %d\n", pid); return -1; } else if (pid == 0) { close(toChild[1]); close(fromChild[0]); // Receive characters from parent process via pipe // one at a time, and count them. int count = 0; printf("child about to read\n"); while(read(toChild[0], &buffer, 1)){ count++; } // Return number of characters counted to parent process. write(fromChild[1], &count, sizeof(count)); close(toChild[0]); close(fromChild[1]); printf("child exits\n"); } else { close(toChild[0]); close(fromChild[1]); // -- running in parent process -- printf("CS201 - Assignment 3 - Chris Gavette\n"); write(toChild[1], &argv[1], 1); // Send characters from command line arguments starting with // argv[1] one at a time through pipe to child process. read(fromChild[0], &nChars, 1); // Wait for child process to return. Reap child process. // Receive number of characters counted via the value // returned when the child process is reaped. close(toChild[1]); close(fromChild[0]); waitpid(pid, &status, 0); printf("child counted %d chars\n", nChars); printf("parent exits\n"); return 0; } } 

Le processus enfant semble se bloquer même si j’ai fermé les deux extrémités des deux tuyaux.

Pour les débutants, c’est faux.

 write(toChild[1], &count, 1) 

Cela consortingbuera éventuellement à votre problème. count est un caractère int , not char ou unsigned char . Vous devez envoyer sizeof(count) . En outre, la fonction de lecture lors de la frappe d’une erreur renverra EOF, qui est différent de zéro. Votre condition de sortie enfant n’est donc pas appropriée. Ça devrait ressembler a quelque chose comme ca:

 while(read(toChild[0], &buffer, 1) == 1) 

Enfin, votre processus parent doit parcourir chaque argument dans argv[] envoyant chacun un tampon de taille strlen .

Je suis presque certain que c’est ce que vous essayez de faire. Notez que pour préserver la santé mentale en sachant quel descripteur est utilisé dans un but spécifique, je préfère utiliser un #define pour noter ce que chaque processus utilise pour la lecture et l’écriture. Cela peut être étendu à n’importe quel nombre de processus, du moins, ce qui, j’en suis sûr, n’est pas très éloigné de la prochaine tâche:

 #include  #include  #include  #include  #include  #include  #include  // P0_READ - parent read source // P0_WRITE - parent write target // P1_READ - child read source // P1_WRITE - child write target #define P0_READ 0 #define P1_WRITE 1 #define P1_READ 2 #define P0_WRITE 3 #define N_PIPES 4 int main(int argc, char **argv) { int fd[N_PIPES], count = 0, i; pid_t pid; char c; if (pipe(fd) || pipe(fd+2)) { perror("Failed to open pipe(s)"); return EXIT_FAILURE; } // fork child process if ((pid = fork()) == -1) { perror("Failed to fork child process"); return EXIT_FAILURE; } // child process if (pid == 0) { // close non P1 descriptors close(fd[P0_READ]); close(fd[P0_WRITE]); // get chars from input pipe, counting each one. while(read(fd[P1_READ], &c, 1) == 1) count++; printf("Child: count = %d\n", count); write(fd[P1_WRITE], &count, sizeof(count)); // close remaining descriptors close(fd[P1_READ]); close(fd[P1_WRITE]); return EXIT_SUCCESS; } // parent process. start by closing unused descriptors close(fd[P1_READ]); close(fd[P1_WRITE]); // send each arg for (i=1; i 

Consortingbution

 ./progname argOne argTwo 

Sortie

 Child: count = 12 Parent: count = 12 

Edit: Single Pipe avec statut de retour d'enfant

Il semble que, d'après les commentaires de la question initiale, votre affectation nécessite de récupérer le statut de retour du processus enfant en tant que nombre de résultats plutôt que de le renvoyer dans un tube. Pour ce faire, vous pouvez le faire avec une seule paire de descripteurs de tuyau. Je préfère la première méthode, mais cela fonctionne aussi bien:

 #include  #include  #include  #include  #include  #include  #include  // P0_WRITE - parent write target // P1_READ - child read source #define P1_READ 0 #define P0_WRITE 1 #define N_PIPES 2 int main(int argc, char **argv) { int fd[N_PIPES], count = 0; pid_t pid; char c; if (pipe(fd)) { perror("Failed to open pipe(s)"); return EXIT_FAILURE; } // fork child process pid = fork(); if (pid == -1) { perror("Failed to fork child process"); return EXIT_FAILURE; } if (pid == 0) { // close non P1 descriptors close(fd[P0_WRITE]); // Return number of characters counted to parent process. while(read(fd[P1_READ], &c, 1) == 1) ++count; close(fd[P1_READ]); printf("Child: count = %d\n", count); return count; } // parent process. start by closing unused descriptors close(fd[P1_READ]); // eacn each arg entirely for (int i=1; i 

Les résultats sont les mêmes, mais notez que le débogage est indispensable car la plupart des débogueurs émettent un signal sur votre processus enfant et le statut de sortie réel est perdu. Sur mon Mac, par exemple, exécutez ceci sous les voyages Xcode:

 Failed to wait for child process: Interrupted system call 

en cours d'exécution depuis la ligne de commande donne:

 Child: count = 12 Parent: count = 12 

L'une des nombreuses raisons pour lesquelles je préfère la méthodologie à deux tubes.