关闭管道写入端会失败而导致读取进程阻塞吗?

问题描述 投票:0回答:1

让我们考虑一个常见的场景

  1. 创建管道和叉子(假设没有发生错误)

    pipe (pipefd); fork();
    
  2. 父进程写入管道,关闭它并等待其子进程

    write(pipefd[1], str, strlen(str);
    close(pipefd[1]);
    wait(NULL);
    
  3. 子进程从管道中读取数据直到EOF

    while ((len = read(pipefd[0], buf, BUF_SIZE)) > 0)
        write(STDOUT_FILENO, &buf, len);
    close(pipefd[0]);
    exit(len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
    
由于某些原因,在父级上调用

close(pipefd[1])

 可能会失败并出现错误。在这种情况下,孩子的结局会怎样呢?孩子是否也应该收到读取错误或可以在 
read
 通话中保持阻塞状态?在这种情况下,此代码是否会导致死锁(子级位于 
read
,父级位于 
wait
)?处理这种情况的正确方法是什么?

c pipe posix
1个回答
0
投票
作为初步事项,您不会描述子进程关闭

pipefd[1]

。不管怎样,孩子必须这样做才能期望它的 
read(pipefd[0])
 调用报告 EOF 条件。

在父级上调用 close(

pipefd[1]

) 可能会失败并显示
由于某些原因出现错误。

是的,一般来说,从某种意义上说,

close()

可能会返回-1并设置
errno
。但这并不一定意味着文件描述符没有关闭。这是一个棘手的情况。您应该阅读 
close(2) 手册页 的注释部分进行讨论,该部分太长,无法在此处重现。

孩子的结局会发生什么 案件?如果孩子也收到读取错误或可能仍然被阻止

read

 电话?

这要看情况。在提出问题的一般性水平上没有答案。

在某些系统(例如 Linux)上,

close()

 
always 会关闭指定的文件描述符,前提是它最初是有效的打开文件描述符,即使它最终报告错误也是如此。在这样的系统上,孩子的 read()
 很可能(但不能保证)不会无限期地阻塞。

这段代码会导致死锁吗(

read

上的孩子,
家长在 
wait
)在这种情况下?

如果父进程忽略了管道写入端的失败?是的,孩子继续阻塞

close()

 是在 POSIX 允许的可能性范围内。如果父母继续对孩子进行
read()
,那么这可能会陷入僵局。
处理这个问题的正确方法是什么
情况?

如果

wait()
失败,则父级应以某种方式报告错误 - 例如,诊断消息、以失败状态退出或返回错误代码。它还可以考虑尝试强制子进程终止,例如,向其发送

close()

 甚至 
SIGTERM
。即使不杀死孩子,在这种情况下您也必须假设可能存在数据丢失或损坏,因此杀死孩子并不会让您在这方面的情况变得更糟。

© www.soinside.com 2019 - 2024. All rights reserved.