8
votes

Les pipes de Unix sont-elles censées être uni-directionnelles?

Regardez le code suivant:

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>

main() {
    int pipdes[2];
    char buff[50];
    const char parent[]="Parent Writes. Child Reads\n";
    const char child[]="Child Writes. Parent Reads\n";
    if(pipe(pipdes)==0) {
        pid_t pid=fork();
        if(pid<0)
              printf("Error\n");
        if(pid==0){
            read(pipdes[0],buff,50);
            printf("Parent: %s",buff);
            write(pipdes[1], child, strlen(child));
            exit(0);
        }
        else if(pid>0) {
            write(pipdes[1], parent, strlen(parent));
            wait(pid);
            read(pipdes[0], buff, 50);
            printf("Child: %s", buff);
        }
    }
    else
        printf("Error in pipe\n");
}


2 commentaires

Cela ne devrait-il pas être pid == 0 , au lieu de pid <0 ? Je suis sûr que fourchette () renvoie 0 au parent et ne renvoie que négatif dans une erreur.


Ouais, désolé pour le ça. Je n'ai pas copié le code correctement.


3 Réponses :


20
votes

sur certains systèmes, les tuyaux peuvent être bidirectionnels. Mais ils ne doivent pas être, et toute hypothèse qu'elles seront non portatives. En particulier, ils ne sont pas sous Linux.

tel qu'il est, votre code a un problème - les deux processus tentent de lire et d'écrire sur le même tuyau. L'utilisation prévue pour les pipes est que l'enfant écrit et le parent lit, ou vice versa. La voie actuelle que vous faites les choses fonctionne pour vous en ce moment, car vous lisez et écrivez une fois et attendez sur l'enfant. Mais quand vous boucle en essayant de faire des choses comme vous faites, vous ne pouvez pas attendre - et sans la synchronisation, l'enfant sera souvent (mais pas toujours!) Finir par la lecture de ce qu'elle avait voulu Pour envoyer au parent, et vice versa.

Si vous souhaitez que des données circulent dans les deux sens, vous pouvez utiliser deux paires de tuyaux. Appelons-les parent_pipe et enfant_pipe . Le parent lirait depuis parent_pipe [0] et écrire sur enfant_pipe [1] , et l'enfant lirait depuis enfant_pipe [0] et écrire à parent_pipe [1] . xxx

Alternativement, vous pouvez utiliser une paire de prises UNIX créées avec socketpair (AF_LOCAL, SOCK_STREAM, 0 , Sockdes) (où sockdes est ce que nous avons renommé pipdes à, car il s'agit des sockets maintenant et non des tuyaux). L'enfant lirait et écrit à sockdes [0] et le parent lirait et écrivez à SOCKDES [1] . Ou vice versa.


5 commentaires

Eh bien, c'est exactement ce que je suis incapable de comprendre, à l'exception de la partie PID <0 (que j'ai copiée à tort), le code fonctionne bien et le parent et l'enfant lisent et écrivent dans le bon ordre.


C'est parce que (1) vous êtes attendre sur l'enfant. Normalement, vous venez de lire l'entrée; Avec le attendre , vous écrivez, en attente de la lecture et de l'écriture de l'enfant, puis de lire. Cela fonctionne pour l'instant, mais (2) Vous ne faites qu'une itération lecture / écriture (c'est pourquoi attendre (PID) fonctionne). Dans une boucle, attendre ne fonctionnera pas - il ne reviendrait que lorsque l'enfant meurt. Si vous lisez et écrivez ... Dites ... 50 fois, les chances sont bonnes qu'avec une paire de tuyaux, l'enfant lira ce qu'il vient d'envoyer au parent, et inversement. HOLD ON, LEMME EDIT.


Donc, ce que vous dites, c'est que si son seul message à envoyer et à recevoir, un tuyau peut alors fonctionner bidirectionnelle. Ce qui signifie que les tuyaux ne sont pas unidirectionaux en règle générale, son juste gênant d'utiliser ensuite bidirectionnelle dans la plupart des cas.


Non, le fait que deux processus puissent partager le même tuyau ne leur rend pas bidirectionnel. S'ils étaient bidirectionnels, l'enfant pouvait lire du tuyau [0] et écrire sur la pipe [1], et le parent pourrait écrire à pipe [0] et lire de la pipe [1]. Ce que vous avez actuellement est deux processus partageant un tuyau unidirectionnel de manière à travailler semi-accidentellement.


D'ACCORD. Donc, c'est le même tuyau qui fonctionne uni-directionnel et mon code peut échanger l'expéditeur et le récepteur, et cela fonctionne dans le cas aussi simple que cela.



3
votes

Non, ils ne sont pas. Il y a eu des systèmes avec des tuyaux bidirectionnels (Soleil, IIRC). Si vous avez vraiment besoin d'un tuyau bidirectionnel, vous pouvez utiliser SocketPair ().


0 commentaires

5
votes

Dans POSIX.1-2001, les tuyaux sont unidirectionnels. De la page man:

tuyau () crée une paire de descripteurs de fichier, pointant vers une pipe inode, et les place dans la matrice pointée par des griefs. Filedes [0] est pour Lecture, Filedes [1] est pour écrire.

D'ailleurs, votre utilisation de Fork est incorrecte: Fork Retours pid> 0 pour le parent et pid == == 0 pour l'enfant. pid <0 signifie qu'il y avait une erreur.


0 commentaires