【问题标题】:UNIX FIFO: the process hangs if I don't close the input side of the fifoUNIX FIFO:如果我不关闭 fifo 的输入端,则进程挂起
【发布时间】:2011-01-12 14:00:10
【问题描述】:

我刚开始使用 UNIX FIFO,在尝试我的第一个 FIFO 程序时发现了一些东西。程序是这样工作的:创建 FIFO 后,使用fork() 函数启动两个进程。子进程读取父亲通过 FIFO 传递给他的内容,并将其打印在屏幕上。交换的数据是指定为参数的字符串。问题是:在父亲部分,如果我忘记关闭 FIFO 的输入端(意味着我排除了close(fd) 行),即使进程之间的数据交换正确,程序也会挂起。否则,一切正常,程序终止而不会挂起。谁能解释一下为什么?

感谢您的耐心等待。下面是main函数的代码:

int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("An argument must be specified\n");
        return -1;
    }   

    int ret = mkfifo("./fifo.txt", 0644);
    char buf;

    if(ret < 0)
    {
        perror("Error creating FIFO");
        return -1;
    }

    pid_t pid = fork();

    if(pid < 0)
    {
        perror("Error creating child process");
        return -1;
    }

    if(pid == 0) /* child */
    {
        int fd = open("./fifo.txt", O_RDONLY); /* opens the fifo in reading mode */

        while(read(fd, &buf, 1) > 0)
        {
            write(STDOUT_FILENO, &buf, 1);
        }
        write(STDOUT_FILENO, "\n", 1);
        close(fd);
        return 0;
    }
    else /* father */
    {
        int fd = open("./fifo.txt", O_WRONLY); /* opens the fifo in writing mode */

        write(fd, argv[1], strlen(argv[1]));
        close(fd);
        waitpid(pid, NULL, 0);
        return 0;
    }
}

【问题讨论】:

  • 可能是子进程卡住了,因为它正在等待父亲关闭 FIFO,但由于父亲不这样做,孩子永远等待 FIFO 关闭,而父亲还要等待孩子终止吗?

标签: c unix fifo


【解决方案1】:

read(2) 阻塞,直到有可用字符或通道在另一端关闭。父进程必须关闭管道才能让最后一个子进程read() 返回。如果您在父亲中省略close(fd),孩子将阻塞read(),直到父亲退出(自动关闭管道),但父亲将挂在waitpid(),直到孩子退出。

【讨论】:

  • 当然你是对的,我以前怎么可能不明白! read() 函数在 FIFO 另一端的父进程关闭它之前不会返回 0。非常感谢您的帮助!
【解决方案2】:

首先要做的是:您发布的代码存在几个问题。

  1. 没有#include 指令,因此您调用的任何函数都没有原型。 C89 需要可变参数函数的原型,例如printf(); C99 需要 所有 函数的原型。 C89 和 C99 都需要在 O_RDONLYO_WRONLYSTDOUT_FILENONULL 的范围内声明。
  2. -1 不是 main() 的允许返回值。
  3. C89 不允许混合声明和语句。

一个小问题:通常的命名是“父母和孩子”,而不是“父亲和孩子”。

我已修改您的程序以更正此问题并提高可读性:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("An argument must be specified\n");
        return 1;
    }

    int ret = mkfifo("./fifo.txt", 0644);
    char buf;

    if (ret < 0) {
        perror("Error creating FIFO");
        return 1;
    }

    pid_t pid = fork();

    if (pid < 0) {
        perror("Error creating child process");
        return 1;
    }

    if (pid == 0) { /* child */
        int fd = open("./fifo.txt", O_RDONLY); /* opens the fifo in reading mode */

        while(read(fd, &buf, 1) > 0) {
            write(STDOUT_FILENO, &buf, 1);
        }
        write(STDOUT_FILENO, "\n", 1);
        close(fd);
        return 0;
    } else { /* parent */
        int fd = open("./fifo.txt", O_WRONLY); /* opens the fifo in writing mode */

        write(fd, argv[1], strlen(argv[1]));
        close(fd);
        waitpid(pid, NULL, 0);
        return 0;
    }
}

但最重要的是,您没有提及您使用的是什么操作系统和编译器。

我无法重现该问题,我怀疑它可能与上面列出的问题之一有关。

【讨论】:

  • 呸,我当然无法重现您的问题 - 我编译并运行了列出的程序,而不是按照您指定的删除 close() 语句。 JeremyP 所说的。
  • JeremyP,它是 C89 或 C99 或从其中之一派生的某种方言;在任何情况下,由于缺少 O_RDONLYO_WRONLYSTDOUT_FILENONULL 的声明(或宏定义),即使使用最宽容的编译器,该程序也不会按照列表进行编译。
  • 当然我的代码还包含必要的包含指令,否则它永远不会编译。为简洁起见,我决定只引用 main 函数。无论如何,非常感谢您的建议,老实说我不知道​​主函数的返回值不允许为-1。我使用的操作系统是 Ubuntu 10.04,编译器是 GCC 版本 4.4.3。
  • 抱歉,我并没有质疑您的观点,即代码无法按照问题中列出的方式编译。这实际上只是您关于混合声明和代码的第 3 点似乎有点严厉,因为它适用于 C89,但不适用于 C99,除了使用 Visual Studio 的人之外,每个人现在都有,对于他们来说,这整个问题是无关紧要的。
  • 我不明白 main 不允许返回 -1 。这样做的依据是什么?
猜你喜欢
  • 2011-08-22
  • 2012-01-14
  • 2013-06-17
  • 1970-01-01
  • 2020-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多