2011-07-08 2 views
3

Donc j'essayais d'exécuter une commande système (ou exec, ou autre) à un processus fils après un fork(), et de lui envoyer une entrée, puis d'obtenir sa sortie . Cela ressemble à ceci après fork(), et pc et cp sont des pipes parent-enfant et parent-enfant.pipe, fork, et IPC non bloquant

case 0: 
     /* Child. */ 
     close(STDOUT_FILENO); /* Close current stdout. */ 
     dup2(cp[1], STDOUT_FILENO); 

     close(STDIN_FILENO); 
     dup2(pc[0], STDIN_FILENO); 

     close(pc[1]); 
     close(cp[0]); 
     execlp("cat", "cat", NULL); 
     exit(1); 
    default: 
     /* Parent. */ 
     /* Close what we don't need. */ 
     printf("Input to child:\n"); 

     string theinput("Hey there baby"); 
     write(pc[1], theinput.c_str(), theinput.size()); 
     close(pc[1]); 

     cout << "The input : " << theinput << endl; 


     printf("\nOutput from child:\n"); 
     close(cp[1]); 
     while(read(cp[0], &ch, 1) == 1) 
     { 
      write(1, &ch, 1); 
      outcount++; 
     } 

     exit(0); 

Maintenant, il semble fonctionner très bien (si vous voulez que le code: http://pastebin.com/Fh7GrxYm), mais quand je parlais à #posix sur irc, ils devenaient fous, sur la façon dont cela peut potentiellement bloquer, et comment "dépend de la façon dont le noyau se sent".

Il y avait un billet de blog msdn de la même chose: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx

Comment peut-on empêcher le blocage, le cas échéant, etc?

Répondre

1

Dans votre cas, le blocage peut se produire lorsque le processus parent atteint cette ligne:

write(pc[1], theinput.c_str(), theinput.size()); 

Si « theinput » est beaucoup de données alors le processus parent peut remplir le tuyau pc. Le processus enfant (cat ici) pourrait en lire une partie mais pas la totalité. cat vont-ils vous le faire écho? Mais encore une fois si c'est beaucoup de données, il peut remplir le tuyau cp et bloquera jusqu'à ce que quelqu'un lise les données de ce tuyau. Ce qui n'arrivera jamais parce que le processus parent est bloqué en attendant que le tuyau pc soit drainé et n'atteigne jamais le code qui consomme le contenu du tuyau cp. IMPASSE. Comme vos copains IRC l'ont dit, que cela se produise ou non dépend de beaucoup de choses telles que la quantité de données impliquées, la quantité de données qu'un tuyau peut contenir avant qu'il ne bloque (un paramètre dépendant du noyau), le montant de stdio ou autre tampon effectuée par le parent ou d'un processus d'enfants, etc ...

Vos options sont:

  1. Utiliser deux processus pour contrôler la commande externe: celui qui alimente les données et qui se lit les résultats de retour. Vous devrez deux fois fork() pour cela. Cela ressemble beaucoup à un pipeline shell. Classiquement, la source de données ultime est le processus petit-enfant, le filtre est le parent intermédiaire et le puits de données ultime du processus de subvention.

  2. Utilisez deux threads pour contrôler la commande externe. Similaire à l'option précédente.

  3. Utilisez des E/S non bloquantes pour contrôler la commande externe. Définissez les deux descripteurs de fichiers en mode non bloquant en utilisant fcntl() et configurez une boucle d'événement en utilisant poll() ou select() pour attendre que l'un des descripteurs de fichier soit prêt. Lorsque l'un ou l'autre descripteur de fichier est prêt, préparez-le à write() pour ne terminer que partiellement et à read() pour ne pas tout lire en même temps.

  4. Utilisez une boucle d'événement existant comme glib's, configurez vos tuyaux comme IO Channels et watch them de savoir quand il est temps de lire ou écrire des données. Similaire à l'option précédente mais utilise un framework existant pour que vous puissiez l'intégrer à une boucle d'événement d'application existante.

BTW: Votre exit(1) devrait être _exit(1) pour empêcher la bibliothèque C d'invoquer de manière inappropriée des crochets de sortie à temps dans le processus de l'enfant de courte durée.