C Named pipe (fifo). Parent process gets stuck

2019-07-28 08:51发布

问题:

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);
}
}

回答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.



回答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.



标签: c fork pipe fifo