c - 使用 select() 与 pipe() 和 fork() 结合使用的奇怪行为
问题描述
给定以下代码段:
#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);
}
}
如果片段按原样运行。程序将阻塞 5 秒。select 等待管道的读取端准备好读取一些数据,这永远不会发生并且达到超时。
但是,如果我close(writeend);
在 fork 之后在父进程中取消注释,则在子进程终止后选择停止阻塞(返回“1”,而不是“-1”,这是读取端的文件描述符)。
我不明白后来的行为。我想我将不得不pselect
等待管道读取端的数据或接收 SIGCHLD 的父进程,如文档中所建议:https ://man7.org/linux/man-pages/man2/ select.2.html
pselect() 系统调用允许应用程序安全地等待,直到文件描述符准备好或直到捕获到信号。
有什么见解吗?
编辑:您可以尝试使用:https ://www.programiz.com/cpp-programming/online-compiler/
解决方案
正如博多在评论中指出的那样:
如果您在父级和子级中都关闭了管道的写入端(隐式在退出时),读取将检测到 EOF。
解释为什么在父进程中关闭写端并且子进程终止时选择停止阻塞(因此关闭其管道的写端)
如果写端没有在父进程中关闭,则即使在子进程中关闭了对 read 的调用,它仍然会在父进程中阻塞,因此select
会继续阻塞。
我缺少的部分是当管道的所有写端都关闭时,读取检测 EOF 并且不再阻塞。
推荐阅读
- python - 对于带有 numpy/pandas 的循环(遍历列标题)
- php - 在表单页面上显示表单错误消息
- azure - Xamarin 文本 blob Azure 存储
- c# - C# UWP BluetoothLEDevice.FromIdAsync 停止工作
- azure - Azure:Microsoft.Compute 资源提供商在“注册”中停留了大约一天
- vb.net - 在 uwp 中处理 excel 文件
- javascript - 更新数据表输入字段并在输入更改时自动计算总数
- rust - 从 Rust 向 C 函数提供`char **` 参数?
- c++ - Qt:窗口图标质量不好
- c# - 如何通过我的实体基类上的属性过滤从实体框架返回的所有内容