Home > OS >  how to use two pipes between three process in c?
how to use two pipes between three process in c?

Time:12-14

I trying to write my program in C with pipes. I have three process: P (father), R (child) and W (child). P and R comunicate beetween first pipes. P and W comunicate beetween second pipes. The child R reading the input file, passing every row to father P using the first pipes. Father P reads the words and check if are palindrome, if the word is palindrome the father send it to child W.

This is my code:

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

#define DIMBUF 1024

int palindroma(const char *stringa)
{
    int len = strlen(stringa);

    int j = 0;
    for (int i = len - 1; i >= 0; i--)
    {
        if (stringa[i] == stringa[j])
        {
            j  ;
        }
        else
            return 0;
    }
    return 1;
}

void child_r(int piper, const char *filename, char tmp[DIMBUF])
{
    FILE *w_stream, *file;

    if ((w_stream = fdopen(piper, "w")) == NULL)
    {
        perror("writer piper_rp");
        exit(1);
    }

    printf("Sono il figlio R\n");

    if ((file = fopen(filename, "r")) == NULL)
    {
        perror("apertura file");
        exit(1);
    }

    while (fgets(tmp, DIMBUF, file) != NULL)
    {
        printf("\tLeggo dal file: %s", tmp);
        fputs(tmp, w_stream);
    }
    fclose(file);
    fclose(w_stream);
}

void child_w(int piper, char tmp[DIMBUF])
{
    FILE *r_stream;

    if ((r_stream = fdopen(piper, "r")) == NULL)
    {
        perror("reader");
        exit(1);
    }

    while (fgets(tmp, DIMBUF, r_stream) != NULL)
    {
        printf("\tMessaggio ricevuto: %s\n", tmp);
    }

    fclose(r_stream);
    exit(0);
}

void father(int piper_rp, char tmp[DIMBUF], int piper_pw)
{

    FILE *r_stream, *w_stream;
    int len;

    if ((r_stream = fdopen(piper_rp, "r")) == NULL)
    {
        perror("reader");
        exit(1);
    }

    if ((w_stream = fdopen(piper_pw, "w")) == NULL)
    {
        perror("writer piper_pw");
        exit(1);
    }

    while (fgets(tmp, DIMBUF, r_stream) != NULL)
    {
        len = strlen(tmp);
        if (tmp[len - 1] == '\n')
            tmp[len - 1] = 0;

        int pal = palindroma(tmp);

        if (pal)
        {
            printf("\tMessaggio inviato: %s\n", tmp);
            fputs(tmp, w_stream);
        }
    }

    fclose(w_stream);
    fclose(r_stream);
}

int main(int argc, char const *argv[])
{
    /* code */

    int piper_rp[2];
    int piper_pw[2];
    char tmp[DIMBUF];
    const char *filename = argv[1];

    if (argc != 2)
    {
        fprintf(stderr, "Utilizzo %s file.txt \n ", argv[0]);
        exit(1);
    }

    if (pipe(piper_pw) == -1)
    {
        perror("errore pipe_pw");
        exit(1);
    }

    if (pipe(piper_rp) == -1)
    {
        perror("errore pipe_rp");
        exit(1);
    }

    if (fork() == 0)
    {
        close(piper_rp[0]);
        child_r(piper_rp[1], filename, tmp);
    }
    else
    {

        // padre
        sleep(1);
        close(piper_rp[1]);
        close(piper_pw[0]);
        printf("\nSono il padre P\n");
        father(piper_rp[0], tmp, piper_pw[1]);

        if (fork() == 0)
        {
            printf("\nSono il figlio W\n");
            close(piper_pw[1]);
            child_w(piper_pw[0], tmp);
        }
        else
            wait(NULL);
    }

    return 0;
}

and this is my output:

Sono il figlio R
        Leggo dal file: Ciao
        Leggo dal file: Mondo
        Leggo dal file: Ale
        Leggo dal file: emme
        Leggo dal file: piip
        Leggo dal file: veffev
        Leggo dal file: Scatola
        Leggo dal file: computer
        Leggo dal file: america
        Leggo dal file: abba
        Leggo dal file: acca
        Leggo dal file: cielo
        Leggo dal file: lampada
        Leggo dal file: effe
Sono il padre P
        Messaggio inviato: emme
        Messaggio inviato: piip
        Messaggio inviato: veffev
        Messaggio inviato: abba
        Messaggio inviato: acca
        Messaggio inviato: effe

Why the child W doesn't have an output ? Why the program never enter to the second fork ?

Please help me

CodePudding user response:

You don't close enough pipe descriptors.

Rule of thumb: If you dup2() one end of a pipe to standard input or standard output, close both of the original file descriptors from pipe() as soon as possible. In particular, that means before using any of the exec*() family of functions. The rule also applies with either dup() or fcntl() with F_DUPFD.


Also, as pointed out by Aconcagua in a comment, you don't fork child W until far too late.

You don't wait for all the children to exit.

I see no merit in passing the tmp buffer from main() to each of the process functions — it can be a local variable in each function.

Here is some code that works, I think.

/* SO 7478-4122 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

#define DIMBUF 1024

static int palindroma(const char *stringa)
{
    int len = strlen(stringa);

    for (int j = 0, i = len - 1; i > j; i--, j  )
    {
        if (stringa[i] != stringa[j])
            return 0;
    }
    return 1;
}

static void child_r(int piper, const char *filename)
{
    char tmp[DIMBUF];
    FILE *w_stream, *file;

    if ((w_stream = fdopen(piper, "w")) == NULL)
    {
        perror("writer piper_rp");
        exit(EXIT_FAILURE);
    }

    printf("Sono il figlio R (%d)\n", getpid());

    if ((file = fopen(filename, "r")) == NULL)
    {
        perror(filename);
        exit(EXIT_FAILURE);
    }

    while (fgets(tmp, sizeof(tmp), file) != NULL)
    {
        printf("\tLeggo dal file: %s", tmp);
        fputs(tmp, w_stream);
    }
    fclose(file);
    fclose(w_stream);
}

static void child_w(int piper)
{
    char tmp[DIMBUF];
    FILE *r_stream;

    printf("Sono il figlio W (%d)\n", getpid());

    if ((r_stream = fdopen(piper, "r")) == NULL)
    {
        perror("reader");
        exit(1);
    }

    while (fgets(tmp, sizeof(tmp), r_stream) != NULL)
        printf("\tMessaggio ricevuto: %s", tmp);

    fclose(r_stream);
}

static void father(int piper_rp, int piper_pw)
{
    char tmp[DIMBUF];
    FILE *r_stream, *w_stream;

    if ((r_stream = fdopen(piper_rp, "r")) == NULL)
    {
        perror("fdopen(piper_rp, \"r\")");
        exit(EXIT_FAILURE);
    }

    if ((w_stream = fdopen(piper_pw, "w")) == NULL)
    {
        perror("fdopen(piper_pw, \"w\")");
        exit(EXIT_FAILURE);
    }

    while (fgets(tmp, sizeof(tmp), r_stream) != NULL)
    {
        tmp[strcspn(tmp, "\n")] = '\0';
        if (palindroma(tmp))
        {
            printf("\tMessaggio inviato: %s\n", tmp);
            fprintf(w_stream, "%s\n", tmp);
        }
    }

    fclose(w_stream);
    fclose(r_stream);
}

int main(int argc, char const *argv[])
{
    int piper_rp[2];
    int piper_pw[2];
    const char *filename = argv[1];

    if (argc != 2)
    {
        fprintf(stderr, "Utilizzo %s file.txt \n ", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (pipe(piper_pw) == -1 ||
        pipe(piper_rp) == -1)
    {
        perror("errore pipe_pw");
        exit(EXIT_FAILURE);
    }

    int pid1;
    int pid2;
    if ((pid1 = fork()) < 0)
    {
        perror("fork()");
        exit(EXIT_FAILURE);
    }
    else if (pid1 == 0)
    {
        close(piper_pw[0]);
        close(piper_pw[1]);
        close(piper_rp[0]);
        child_r(piper_rp[1], filename);
        exit(21);
    }
    else if ((pid2 = fork()) < 0)
    {
        perror("fork()");
        exit(EXIT_FAILURE);
    }
    else if (pid2 == 0)
    {
        close(piper_rp[0]);
        close(piper_rp[1]);
        close(piper_pw[1]);
        child_w(piper_pw[0]);
        exit(32);
    }
    else
    {
        close(piper_rp[1]);
        close(piper_pw[0]);
        printf("\nSono il padre P (%d)\n", getpid());
        father(piper_rp[0], piper_pw[1]);

        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("Child %d exited with status 0x%.4X\n", corpse, status);
    }

    return 0;
}

I tested with this input file:

Ciao
Mondo
Ale
emme
piip
veffev
Scatola
computer
america
abba
acca
cielo
lampada
effe
amanaplanacanalpanama
ablewasiereisawelba

When run, the output was:

Sono il padre P (30483)
Sono il figlio R (30484)
    Leggo dal file: Ciao
    Leggo dal file: Mondo
    Leggo dal file: Ale
    Leggo dal file: emme
    Leggo dal file: piip
    Leggo dal file: veffev
    Leggo dal file: Scatola
    Leggo dal file: computer
    Leggo dal file: america
    Leggo dal file: abba
    Leggo dal file: acca
    Leggo dal file: cielo
    Leggo dal file: lampada
    Leggo dal file: effe
    Leggo dal file: amanaplanacanalpanama
    Leggo dal file: ablewasiereisawelba
Sono il figlio W (30485)
    Messaggio inviato: emme
    Messaggio inviato: piip
    Messaggio inviato: veffev
    Messaggio inviato: abba
    Messaggio inviato: acca
    Messaggio inviato: effe
    Messaggio inviato: amanaplanacanalpanama
    Messaggio inviato: ablewasiereisawelba
    Messaggio ricevuto: emme
    Messaggio ricevuto: piip
    Messaggio ricevuto: veffev
    Messaggio ricevuto: abba
    Messaggio ricevuto: acca
    Messaggio ricevuto: effe
    Messaggio ricevuto: amanaplanacanalpanama
    Messaggio ricevuto: ablewasiereisawelba
Child 30484 exited with status 0x1500
Child 30485 exited with status 0x2000

Note that after stripping the newline to test whether the string is a palindrome, it was necessary to add it when sending the message from the parent to the W child — otherwise, the child gets all the palindromes jammed together in a single line.

  • Related