Problème d'utilisation de DUP2 pour faire en sorte qu'un programme C exécute une commande telle que 'ls / bin | grep grep | grep b '

StackOverflow https://stackoverflow.com/questions/9459627

  •  13-11-2019
  •  | 
  •  

Question

J'ai du mal à utiliser dup2 pour qu'un programme C exécute une commande telle que ls /bin | grep grep | grep b.Lorsque je commente la troisième commande et le canal associé, il s'exécute ls /bin | grep grep bien, mais avec la dernière commande, il revient tout de suite.De plus, lorsque j'entre « ps », les processus sont toujours en cours d'exécution.Je pense que c'est dû à la façon dont je ferme les tuyaux.Mon code est ci-dessous :

int main()
{
    int pipeA[2];
    int pipeB[2];

    pipe(pipeA);
    pipe(pipeB);

    int pidA,pidB,pidC;

    if(pidA = fork())
    {
            close(pipeA[0]);
            dup2(pipeA[1],1);
            close(pipeA[1]);
            execlp("ls","ls","/bin",NULL);
            printf("error\n");
    }

    if(pidB = fork())
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);

            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep","grep","grep",NULL);
            printf("error\n");
    }

    if(pidC = fork())
    {
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep","grep","b",NULL);
            printf("error");
    }


    while(pidA != wait(0)){}

    return 0;
}
Était-ce utile?

La solution

Vous ne fermez pas suffisamment de descripteurs de fichiers.

/* Semi-working code */
int main()
{
    int pipeA[2];
    int pipeB[2];

    pipe(pipeA);
    pipe(pipeB);

    int pidA,pidB,pidC;

    if (pidA = fork())
    {
            close(pipeB[0]);  // "ls" is not going to use the second pipe
            close(pipeB[1]);  // Ditto
            close(pipeA[0]);
            dup2(pipeA[1], 1);
            close(pipeA[1]);
            execlp("ls", "ls", "/bin", (char *)NULL);
            fprintf(stderr, "error executing 'ls'\n");
            exit(1);
    }

    if (pidB = fork())
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);
            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep", "grep", "grep", (char *)NULL);
            fprintf(stderr, "error execing 'grep grep'\n");
            exit(1);
    }

    if (pidC = fork())
    {
            close(pipeA[0]);  // The second grep is not going to use the first pipe
            close(pipeA[1]);  // Ditto
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep", "grep", "b", (char *)NULL);
            fprintf(stderr, "error execing 'grep b'\n");
            exit(1);
    }

    close(pipeA[0]);  // The parent process is not using the pipes at all
    close(pipeA[1]);
    close(pipeB[0]);
    close(pipeB[1]);

    while (pidA != wait(0))
        ;

    return 0; 
}

Parce que tu n'as pas fermé pipeA dans la seconde grep, tu te retrouves avec le premier grep en attente de l'entrée du tuyau la seconde grep est toujours ouvert, même si le processus n'y écrira pas.À cause de cela, le premier grep ne finit pas, donc le second ne finit pas non plus - même si le ls complète.Ces commentaires s'appliqueraient même si le processus parent fermait ses copies des tubes - comme le fait le code corrigé.

Remarquez comment vous finissez par fermer les 4 descripteurs renvoyés par les deux appels à pipe() dans chacun des quatre processus - trois enfants et le processus parent.

Cela laisse un problème résiduel : la hiérarchie des processus est sens dessus dessous en raison de votre utilisation aconventionnelle de if (pidA = fork()).Vous avez un processus enfant qui attend ses parents.Vous devez utiliser :

if ((pidA = fork()) == 0)
{
    /* Be childish */
}

De même pour chacun des deux autres processus.Vous devriez également vérifier le pipe() les appels et le fork() appelle à l’échec, juste pour être sûr.

#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <stdlib.h>

static void err_exit(const char *format, ...);

/* Working code */
int main(void)
{
    int pipeA[2];
    int pipeB[2];

    if (pipe(pipeA) != 0 || pipe(pipeB) != 0)
        err_exit("Failed to create a pipe\n");

    int pidA,pidB,pidC;

    if ((pidA = fork()) < 0)
        err_exit("Failed to fork (A)\n");
    else if (pidA == 0)
    {
            close(pipeB[0]);  // "ls" is not going to use the second pipe
            close(pipeB[1]);  // Ditto
            close(pipeA[0]);
            dup2(pipeA[1], 1);
            close(pipeA[1]);
            execlp("ls", "ls", "/bin", (char *)NULL);
            err_exit("error executing 'ls'\n");
    }

    if ((pidB = fork()) < 0)
        err_exit("failed to fork (B)\n");
    else if (pidB == 0)
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);
            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep", "grep", "grep", (char *)NULL);
            err_exit("error execing 'grep grep'\n");
    }

    if ((pidC = fork()) < 0)
        err_exit("failed to fork (C)\n");
    else if (pidC == 0)
    {
            close(pipeA[0]);  // The second grep is not going to use the first pipe
            close(pipeA[1]);  // Ditto
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep", "grep", "b", (char *)NULL);
            err_exit("error execing 'grep b'\n");
    }

    close(pipeA[0]);  // The parent process is not using the pipes at all
    close(pipeA[1]);
    close(pipeB[0]);
    close(pipeB[1]);

    while (wait(0) != -1)
        ;

    printf("Continuing here...\n");
    sleep(3);
    printf("That's enough of that!\n");

    return 0; 
}

static void err_exit(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    exit(1);
}

Lorsqu'il est trafiqué pour utiliser /usr/bin au lieu de /bin, ce programme fonctionne correctement sur Mac OS X 10.7.3.Il répertorie trois fichiers, puis génère le message « Continuer ici » :

bzegrep
bzfgrep
bzgrep
Continuing here...
That's enough of that!
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top