C Named pipe (fifo). Parent process gets stuck

15,336

Solution 1

You really should be checking the return value on function calls for errors, especially mkfifo() and open().

Your call to wait() is going to cause problems in its current location. Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa1. The parent is waiting for the child to terminate and the child is waiting for a reader process, i.e., the parent, to connect to the FIFO.

1 - see note on open() below for using O_NONBLOCK with a FIFO

Moving the wait() call to just before the parent process exits along with changing the mode in the call to mkfifo() to 0666 seems to resolve some of your immediate problems.

It is also good practice to remove the FIFO when you are finished with it.

unlink("myfifo");

From the open() function documentation in IEEE Std 1003.1-2004:

When opening a FIFO with O_RDONLY or O_WRONLY set:

  • If O_NONBLOCK is set, an open() for reading-only shall return without delay. An open() for writing-only shall return an error if no process currently has the file open for reading.

  • If O_NONBLOCK is clear, an open() for reading-only shall block the calling thread until a thread opens the file for writing. An open() for writing-only shall block the calling thread until a thread opens the file for reading.


The following example is a combination of the code in your original question and the FIFO page of Beej's Guide to Unix IPC:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

#define FIFO_NAME "myfifo"

int main(void)
{
    char buf[256];
    int num, fd;
    pid_t pid;

    if (mkfifo(FIFO_NAME, 0666) < 0)
        perror("mkfifo");

    pid = fork();
    if (pid == 0)
    {
        printf("child - waiting for readers...\n");
        if ((fd = open(FIFO_NAME, O_WRONLY)) < 0)
            perror("child - open");
        
        printf("child - got a reader -- type some stuff\n");
        while (fgets(buf, sizeof(buf), stdin), !feof(stdin))
        {
            if ((num = write(fd, buf, strlen(buf))) < 0)
                perror("child - write");
            else
                printf("child - wrote %d bytes\n", num);
        }

        close(fd);
        exit(0);
    }
    else
    {
        printf("parent - waiting for writers...\n");
        if ((fd = open(FIFO_NAME, O_RDONLY)) < 0)
            perror("parent - open");
        
        printf("parent - got a writer\n");
        do
        {
            if ((num = read(fd, buf, sizeof(buf))) < 0)
                perror("parent - read");
            else
            {
                buf[num] = '\0';
                printf("parent - read %d bytes: \"%s\"\n", num, buf);
            }
        } while (num > 0);

        close(fd);
        wait(0);
    }

    unlink(FIFO_NAME);
    return 0;
}

This example was tested in Linux. Press Ctrl-D to terminate the program.

Solution 2

First of all, try fprintf to stderr instead of printf (to stdout)

The stderr is unbuffered.

Then you can tell what actually gets printed and what does not.

or at least add fflush before waiting for anything.

Share:
15,336
AdrianS
Author by

AdrianS

Updated on June 26, 2022

Comments

  • AdrianS
    AdrianS almost 2 years

    I want to make a simple program, that fork, and the child writes into the named pipe and the parent reads and displays from the named pipe. The problem is that it enters the parent, does the first printf and then it gets weird, it doesn't do anything else, does not get to the second printf, it just ways for input in the console.

    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    void main()
    {
    char t[100];
    mkfifo("myfifo",777);
    pid_t pid;
    pid = fork();
    if (pid==0)
    {
        //execl("fifo2","fifo2",(char*)0);
        char r[100];
        printf("scrie2->");
        scanf("%s",r);
    
        int fp;
        fp = open("myfifo",O_WRONLY);
        write(fp,r,99);
        close(fp);
        printf("exit kid \n");
        exit(0);
    } else
    {
        wait(0);
        printf("entered parent \n"); // <- this it prints
        // whats below this line apparently its not being executed
        int fz; printf("1"); 
        fz = open("myfifo",O_RDONLY); printf("2");
        printf("fd: %d",fz);
        char p[100];
        int size;
        printf("------");
        //struct stat *info;
        //stat("myfifo",info); printf("%d",(*info).st_size);
        read(fz,p,99);
        close(fz);
        printf("%s",p);
    
        printf("exit"); exit(0);
    }
    }
    
  • AdrianS
    AdrianS almost 14 years
    i open the FIFO but i close it in the same process. so it should not block. and i NEED that my parent process to wait after its child, because the child gets input, and i cannot not wait on the first line of the parent because that would mean to begin to read from the fifo, when i dind't even finish to write on it
  • AdrianS
    AdrianS almost 14 years
    now i have: char c[2]; c[1] = 0; c[0]=0; c[0] = strlen(r); // c[0] is lets say 4 write(fp,c,1); //fp is the FIFO then in another process: //open pipe, i check for errors, but there are no errors, so it open fine char c[2]; c[1]=0; c[0]=0; read(fz,c,1); //fz is the pipe //and now c[0] is 0 instead of what it should be, 4
  • jschmier
    jschmier almost 14 years
    It can be difficult following code changes described in comments. You are better off editing your question to show what you've tried. I've added an example to my response that should help you out.
  • jschmier
    jschmier almost 14 years
    There is also a good named pipe tutorial on the Sun Developer Network that you may find useful.