J'essaie de comprendre comment fonctionnent les tuyaux et les fourches. J'ai donc écrit un programme simple où un processus parent envoie un message au processus enfant (ce qui fonctionne très bien). Mais si j'essaye de renvoyer un message à partir du processus enfant en ajoutant le code commenté, cela cesse de fonctionner. Et l'exécution du programme s'arrête après avoir sorti "Parent envoyé: bonjour".
int main() { int child_to_parent[2]; int parent_to_child[2]; pipe(child_to_parent); pipe(parent_to_child); pid_t id = fork(); if (id == 0) { close(parent_to_child[1]); close(child_to_parent[0]); FILE* out = fdopen(child_to_parent[1], "w"); FILE* in = fdopen(parent_to_child[0], "r"); char msg[6]; fscanf(in ,"%s", msg); printf("Child got: %s\n", msg); /* fprintf(out, "hi "); printf("Child sent: hi\n"); */ } else { close(parent_to_child[0]); close(child_to_parent[1]); FILE* in = fdopen(child_to_parent[0], "r"); FILE* out = fdopen(parent_to_child[1], "w"); fprintf(out, "hello"); printf("Parent sent: hello\n"); /* char msg[3]; fscanf(in, "%s", msg); printf("Parent got: %s\n", msg); */ } }
Et je ne comprends pas pourquoi. Ce qui me trouble le plus, c'est pourquoi le processus enfant ne peut même pas recevoir le message après avoir modifié le code. Quelqu'un pourrait-il me dire ce qui ne va pas ou me diriger dans la bonne direction?
3 Réponses :
Première solution utilisant la lecture / écriture pour échanger un nombre quelconque de messages
Ici, j'indique la fin de chaque buffer à lire par un \ n:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra ppp.c pi@raspberrypi:/tmp $ ./a.out Parent sent: hello Child got: hello Child sent: hi Parent got: hi Parent sent: how-are-you? Child got: how-are-you? Child sent: fine,you? Parent got: fine,you? Parent sent: fine-too Child got: fine-too
Compilation et exécution:
#include <stdio.h> #include <unistd.h> int main() { int child_to_parent[2]; int parent_to_child[2]; pipe(child_to_parent); pipe(parent_to_child); pid_t id = fork(); if (id == 0) { close(parent_to_child[1]); close(child_to_parent[0]); FILE* out = fdopen(child_to_parent[1], "w"); FILE* in = fdopen(parent_to_child[0], "r"); char msg[16], c; fscanf(in ,"%s%c", msg, &c); printf("Child got: %s\n", msg); fprintf(out, "hi "); fflush(out); printf("Child sent: hi\n"); fscanf(in ,"%s%c", msg, &c); printf("Child got: %s\n", msg); fprintf(out, "fine,you? "); fflush(out); printf("Child sent: fine,you?\n"); fscanf(in ,"%s%c", msg, &c); printf("Child got: %s\n", msg); } else { close(parent_to_child[0]); close(child_to_parent[1]); FILE* in = fdopen(child_to_parent[0], "r"); FILE* out = fdopen(parent_to_child[1], "w"); fprintf(out, "hello\n"); fflush(out); printf("Parent sent: hello\n"); char msg[16], c; fscanf(in, "%s%c", msg, &c); printf("Parent got: %s\n", msg); fprintf(out, "how-are-you? "); fflush(out); printf("Parent sent: how-are-you?\n"); fscanf(in, "%s%c", msg, &c); printf("Parent got: %s\n", msg); fprintf(out, "fine-too "); fflush(out); printf("Parent sent: fine-too\n"); } }
Il est également possible d'utiliser fread / fwrite , fflush est nécessaire après fwrite pour ne pas être bloqué. Il n'est heureusement pas nécessaire de fermer le pipe après l'envoi pour pouvoir lire et répondre, sinon un seul message peut être échangé. J'utilise toujours \ n pour indiquer la fin du tampon envoyé:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra pp.c pi@raspberrypi:/tmp $ ./a.out Parent sent:hello Child got:hello Child sent:hi Parent got:hi Parent sent:how are you ? Child got:how are you ? Child sent:fine, and you ? Parent got:fine, and you ? Parent sent:fine too Child got:fine too
Compilation et exécution:
#include <stdio.h> #include <unistd.h> #include <string.h> void rd(FILE * fd, int child) { char c; int first = 1; do { if (!fread(&c, 1, 1, fd)) break; if (first) { printf("%s got:", (child) ? "Child" : "Parent"); first = 0; } putchar(c); } while (c != '\n'); } void wr(FILE * fd, const char * msg, int child) { fwrite(msg, strlen(msg), 1, fd); fflush(fd); printf("%s sent:%s", (child) ? "Child" : "Parent", msg); } int main() { int child_to_parent[2]; int parent_to_child[2]; pipe(child_to_parent); pipe(parent_to_child); pid_t id = fork(); if (id == 0) { close(parent_to_child[1]); close(child_to_parent[0]); FILE* out = fdopen(child_to_parent[1], "w"); FILE* in = fdopen(parent_to_child[0], "r"); rd(in, 1); wr(out, "hi\n", 1); rd(in, 1); wr(out, "fine, and you ?\n", 1); rd(in, 1); } else { close(parent_to_child[0]); close(child_to_parent[1]); FILE* in = fdopen(child_to_parent[0], "r"); FILE* out = fdopen(parent_to_child[1], "w"); wr(out, "hello\n", 0); rd(in, 0); wr(out, "how are you ?\n", 0); rd(in, 0); wr(out, "fine too\n", 0); } }
Et enfin si vous voulez utiliser fscanf ("% s", ...)
vous devez envoyer un séparateur (un espace ou \ n par exemple) après le mot pour ne pas bloquer fscanf et bien sûr pour lire également le caractère séparateur , le fflush est nécessaire après le fwrite .
Si je change un peu votre programme:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra p.c pi@raspberrypi:/tmp $ ./a.out Parent sent:hello Child got:hello Child sent:hi Parent got:hi Parent sent:how are you ? Child got:how are you ? Child sent:fine, and you ? Parent got:fine, and you ? Parent sent:fine too Child got:fine too
Compilation et exécution:
#include <stdio.h> #include <unistd.h> #include <string.h> void rd(int fd, int child) { char c; int first = 1; do { if (!read(fd, &c, 1)) break; if (first) { printf("%s got:", (child) ? "Child" : "Parent"); first = 0; } putchar(c); } while (c != '\n'); } void wr(int fd, const char * msg, int child) { write(fd, msg, strlen(msg)); printf("%s sent:%s", (child) ? "Child" : "Parent", msg); } int main() { int child_to_parent[2]; int parent_to_child[2]; pipe(child_to_parent); pipe(parent_to_child); pid_t id = fork(); if (id == 0) { close(parent_to_child[1]); close(child_to_parent[0]); rd(parent_to_child[0], 1); wr(child_to_parent[1], "hi\n", 1); rd(parent_to_child[0], 1); wr(child_to_parent[1], "fine, and you ?\n", 1); rd(parent_to_child[0], 1); } else { close(parent_to_child[0]); close(child_to_parent[1]); wr(parent_to_child[1], "hello\n", 0); rd(child_to_parent[0], 0); wr(parent_to_child[1], "how are you ?\n", 0); rd(child_to_parent[0], 0); wr(parent_to_child[1], "fine too\n", 0); } }
fscanf
lit jusqu'à ce qu'un espace blanc (comme indiqué par isspace
) soit trouvé lorsque vous utilisez % s
, mais vous n'envoyez pas une. Donc fscanf
ne revient jamais, car il attend l'espace blanc.
Utilisez fread
et fwrite
au lieu de fscanf
et fprintf
et vos tubes fonctionneront.
@ ThomasPadron-McCarthy Ce n'est pas le cas si le code commenté est de nouveau ajouté. En ce moment, le processus se termine, fermant le flux; si le code commenté n'est pas commenté, les deux processus vont dans fscanf
et deviennent bloqués, attendant l'un de l'autre pour envoyer un caractère d'espacement.
Dans le parent et dans l'enfant, lorsque vous avez fini d'écrire dans le tube, videz les tampons avec fflush
et fermez le tube. > Voici un programme légèrement modifié:
Parent sent: hello Parent gonna read... Child gonna read... Child got: hello Child sent: hi Parent got: hi
Sortie lorsque je l'exécute:
#include <sys/types.h> #include <unistd.h> #include <stdio.h> FILE *fdopen(int fd, const char *mode); int main() { int child_to_parent[2]; int parent_to_child[2]; pipe(child_to_parent); pipe(parent_to_child); pid_t id = fork(); if (id == 0) { close(parent_to_child[1]); close(child_to_parent[0]); FILE* out = fdopen(child_to_parent[1], "w"); FILE* in = fdopen(parent_to_child[0], "r"); char msg[6]; printf("Child gonna read...\n"); fscanf(in ,"%s", msg); printf("Child got: %s\n", msg); fprintf(out, "hi"); fflush(out); printf("Child sent: hi\n"); close(child_to_parent[1]); } else { close(parent_to_child[0]); close(child_to_parent[1]); FILE* in = fdopen(child_to_parent[0], "r"); FILE* out = fdopen(parent_to_child[1], "w"); fprintf(out, "hello"); printf("Parent sent: hello\n"); fflush(out); close(parent_to_child[1]); char msg[3]; printf("Parent gonna read...\n"); fscanf(in, "%s", msg); printf("Parent got: %s\n", msg); } }
Probablement à cause de la mise en mémoire tampon. Je recommande de ne pas mélanger stdio /
FILE
avec des descripteurs de fichiers / tubes.Vous devez vider la sortie du parent ou fermer le flux du parent à l'enfant. La sortie sera entièrement mise en mémoire tampon et vous n'écrivez pas une mémoire tampon pleine.
Oui - essayez de mettre
fflush (0);
après l'écriture du parent, mais avant sa lecture.si vous voulez utiliser
fscanf ("% s", ...)
vous devez envoyer un séparateur (un espace ou \ n par exemple) après le mot pour ne pas bloquer fscanf i> et bien sûr pour lire le caractère séparateur après, le fflush est nécessaire après le fwrite . J'ai mis 3 manières dans ma réponse en lecture / écriture puis fread / fwrite (& fflush) puis enfin un petit changement de votre code avec le séparateur supplémentaire (& fflush)