2010-10-11 12 views
3

J'ai un programme c/C++ très simple qui forge un processus fils pour exécuter un autre programme, puis envoie des données à ce programme enfant, et attend la réponse.(c/C++) essayant de forcer EOF du processus parent envoyant l'entrée au processus enfant

Le programme enfant lit à partir de stdin et attend EOF avant de continuer. Mon problème est, le programme enfant reçoit l'entrée initiale de l'écriture de pipe, mais il ne voit jamais un EOF (même si je ferme le tuyau), de sorte qu'il attend éternellement. Je ne suis pas sûr pourquoi la fermeture du tuyau n'implique pas l'EOF pour le stdin de l'enfant?

est ici le code:

http://gist.github.com/621210

+0

Je mis à jour ma réponse. Et comme je pense à cette question, devrait-il avoir l'étiquette "devoirs"? Cela semble vraiment basique. –

+0

Je vous assure que cela n'a rien à voir avec les devoirs. Je suis sorti de l'école depuis des années. Je ne suis pas un codeur c/C++ mais je construis un système de preuve de concept pour une démo que je fais et je suis revenu au code que je n'ai pas écrit comme dans plus de 10 ans. –

Répondre

5

La raison la plus courante de ceci est que vous ne fermez pas l'extrémité d'écriture du tube, donc l'EOF n'est jamais envoyé. L'exemple commun est lorsque vous avez du code qui ressemble à:

int fds[2]; 
pipe(fds); // open a pipe 
if (fork()) { 
    // parent process 
    write(fds[1], ... // write data 
    close(fds[1]); // close it 
} else { 
    // child process 
    while (read(fds[0], ....) > 0) { 
     // read until EOF 

Le problème ici est que la fin d'écriture du tube ne se ferme - le processus parent ferme, mais l'enfant a encore le descripteur d'écriture ouvert . Ainsi, l'enfant ne voit jamais un EOF sur le descripteur de lecture.

La première chose à faire après avoir forci l'enfant est de close(fds[1]);, en fermant sa copie du descripteur d'écriture. De cette façon, lorsque le parent ferme la dernière référence à l'extrémité d'écriture du tube, l'enfant verra EOF à la fin de la lecture.

Modifier

regardant le lien que vous avez ajouté, c'est précisément le problème - l'enfant a toujours la fin d'écriture du tube ouvert sur son stdout. Ne pas dupliquer la fin d'écriture sur stdout chez l'enfant, fermez-le.Envoyer stdout ailleurs (un fichier journal, ou/dev/null)

Modifier

pour la communication bi-drectional, vous aurez besoin de deux tuyaux:

int tochild[2], fromchild[2]; 
pipe(tochild); pipe(fromchild); 
if (fork()) { 
    close(tochild[0]); 
    close(fromchild[1]); 
    //write to tochild[1] and read from fromchild[0] 
} else { 
    dup2(tochild[0], 0); 
    dup2(fromchild[1], 1); 
    close(tochild[0]); close(tochild[1]); 
    close(fromchild[0]); close(fromchild[1]); 
    exec(... 
} 

Vous devez être très Cependant, s'il y a beaucoup de données à envoyer à l'enfant, vous ne pouvez pas les envoyer avant de lire la sortie de l'enfant ou vous risquez de vous retrouver dans une impasse (les deux tuyaux se remplissent et les blocs parent essayer d'écrire plus de données pour l'enfant pendant que l'enfant bloque en essayant de sortir). Vous devez utiliser poll ou select pour indiquer quand il y a des données à lire ou écrire, et vous pouvez mettre les pipes (le parent se termine au moins) en mode non-bloquant.

+0

s'il vous plaît voir les lignes 32 à 37 dans le code lié gist. je les ferme. –

+0

ligne 33 le fait passer à stdout, qui n'est alors jamais fermé –

+0

Comment peut-on fermer le 'stdout' réel de l'enfant si j'ai besoin de l'enfant pour pouvoir répondre au parent après que ce soit fait? J'ai besoin d'un canal de communication bidirectionnel ici. J'ai besoin d'envoyer des données à l'enfant, et j'ai besoin de voir ce que l'enfant répond avec. –

3

Mise à jour avec ce que je pense est le problème: Vous lisez un personnage et à vérifier que le caractère pour EOF. Ce n'est pas ainsi que fonctionne l'appel système read(). Il retournera un 0 quand à EOF. Il n'écrit pas un EOF dans le tampon.

Aussi, je vois que vous lisez un caractère à la fois. C'est une manière terrible de lire des données. Il est plusieurs fois fois plus lent que de lire un grand tampon, disons 4 ou 8 kB.

Je crois que vous avez aussi une erreur commune ici. Vous ne vérifiez pas la valeur de retour de write().

L'appel du système en écriture ne garantit pas l'écriture de toutes les données avant le retour. Il pourrait écrire 4000 octets et revenir. Il renverra le nombre d'octets écrits. Il vous incombe alors de mettre à jour votre pointeur de mémoire tampon et d'appeler à nouveau l'écriture.

Ou il peut renvoyer un code d'erreur et il est important que vous vérifiiez cela.

+0

assez juste. c'est un simple code de preuve de concept. Dans mon test, j'envoie 5 caractères comme entrée. Donc je suppose que je serais surpris si le write() n'en envoyait que la moitié. –

+0

En outre, si je change l'enfant pour lire seulement 5 caractères (au lieu d'attendre EOF), le programme enfant obtient tous les 5 caractères et fonctionne comme prévu. Il semble donc que le seul problème est que j'ai besoin que l'enfant attende une entrée de longueur variable et que l'EOF semble être la bonne façon de le signaler. –

+0

vous vous concentrez sur la mauvaise partie du problème. Je n'ai aucun problème à récupérer le ouptut de l'enfant dans le parent. J'ai des problèmes avec l'enfant qui n'obtient jamais un EOF quand le parent écrit des données dans le tuyau qui est relié au stdin de l'enfant et ferme ensuite le tuyau après l'écriture. –

Questions connexes