【问题标题】:C Named pipe (fifo). Parent process gets stuckC 命名管道 (fifo)。父进程卡住
【发布时间】:2010-05-29 15:07:51
【问题描述】:

我想制作一个简单的程序,即 fork,子进程写入命名管道,父进程从命名管道读取并显示。 问题是它进入父进程,执行第一个 printf,然后它变得很奇怪,它没有做任何其他事情,没有到达第二个 printf,它只是在控制台中输入的方式。

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

【问题讨论】:

    标签: c fork pipe fifo


    【解决方案1】:

    您确实应该检查函数调用的返回值是否有错误,尤其是mkfifo()open()

    您对wait() 的调用将导致其当前位置出现问题。打开一个 FIFO 进行读取通常会阻塞,直到某个其他进程打开同一个 FIFO 进行写入,反之亦然1。父进程正在等待子进程终止,子进程正在等待读取进程,即父进程连接到 FIFO。

    1 - 请参阅下面关于 open() 的注释,了解如何将 O_NONBLOCK 与 FIFO 一起使用

    wait() 调用移到父进程退出之前,同时将调用中的模式更改为mkfifo()0666 似乎可以解决您的一些直接问题。

    用完 FIFO 后将其移除也是一个好习惯。

    unlink("myfifo");
    

    来自open() function documentation in IEEE Std 1003.1-2004

    当打开设置了 O_RDONLY 或 O_WRONLY 的 FIFO 时:

    • 如果设置了 O_NONBLOCK,则只读的 open() 应立即返回。如果当前没有进程打开文件进行读取,则用于只写的 open() 将返回错误。

    • 如果 O_NONBLOCK 被清除,只读的 open() 将阻塞调用线程,直到线程打开文件进行写入。只写的 open() 将阻塞调用线程,直到线程打开文件进行读取。


    以下示例是code in your original questionFIFO 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;
    }

    此示例在 Linux 中进行了测试。按 Ctrl-D 终止程序。

    【讨论】:

    • 我打开了 FIFO,但我在同一个过程中关闭了它。所以它不应该阻塞。我需要我的父进程在它的子进程之后等待,因为子进程得到输入,我不能不在父进程的第一行等待,因为这意味着当我什至没有完成时开始从 fifo 读取写在上面
    • 现在我有:char c[2]; c[1] = 0; c[0]=0; c[0] = strlen(r); // c[0] 可以说是 4 write(fp,c,1); //fp 是 FIFO 然后在另一个进程中: //打开管道,我检查错误,但没有错误,所以它打开了罚款 char c[2]; c[1]=0; c[0]=0;读取(fz,c,1); //fz 是管道 //现在 c[0] 是 0 而不是它应该是的 4
    • 在 cmets.xml 中描述的代码更改可能很困难。您最好编辑您的问题以显示您尝试过的内容。我在回复中添加了一个示例,应该可以帮助您。
    • 在 Sun Developer Network 上还有一个很好的 named pipe tutorial,您可能会发现它很有用。
    【解决方案2】:

    首先,尝试 fprintf 到 stderr 而不是 printf(到 stdout)

    stderr 没有缓冲。

    然后你就可以分辨出什么实际打印出来了,什么没有打印出来。

    或者至少在等待任何东西之前添加fflush

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多