【发布时间】:2021-12-02 17:34:46
【问题描述】:
给定以下 sn-p:
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>
int main() {
int io[2];
pipe(io);
int read_end = io[0], write_end = io[1];
int cpid = fork();
if(cpid == 0) {
close(read_end);
sleep(1);
return 0;
} else {
//close(write_end);
timeval timeout = {5, 0};
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(read_end, &readfds);
int ready = select(read_end + 1, &readfds, NULL, NULL, &timeout);
printf("ready? %d", ready);
}
}
如果 sn-p 按原样运行。程序将阻塞 5 秒。 select 等待管道的读取端准备好读取一些数据,这永远不会发生并且已达到超时。
但是如果我在fork之后取消注释父进程中的close(writeend);,那么一旦子进程选择停止阻塞(返回'1',而不是'-1',这是读取端的文件描述符)终止。
我不明白后来的行为。我想我必须使用pselect 来等待管道读取端的数据或接收 SIGCHLD 的父进程,如文档中所建议:https://man7.org/linux/man-pages/man2/select.2.html
pselect() 系统调用允许应用程序安全地等待 直到文件描述符准备好或直到有信号 抓到了。
有什么见解吗?
编辑:您可以尝试使用:https://www.programiz.com/cpp-programming/online-compiler/
【问题讨论】:
-
请edit您的问题并添加有关您想要实现的行为的更多详细信息。在父进程中创建管道时,
fork之后管道的两端在两个进程中都是打开的。每个进程都应该在使用管道之前关闭未使用的端。只要父级打开了写端并且没有write,read就会阻塞。如果您在父项和子项中都关闭它(隐式退出),read将检测到 EOF。当select返回时,仅意味着后续的read不会阻塞。read将在管道的写端被所有进程关闭时返回 0 -
@G.M.我阅读了文档的这一部分,但是 1) 多线程帐户是否也适用于多进程应用程序? 2)改变行为的不是我从子进程关闭select(读取端)使用的文件描述符,而是我从同一个父进程关闭另一个文件描述符(写入端)在调用 select 之前处理。
-
@Bodo “如果您在父子节点和子节点都关闭它(隐式退出),读取将检测到 EOF。”那是我缺少的部分!我明白现在发生了什么,感谢您的回答。