c - 如何避免 read() 在以下情况下挂起?
问题描述
我有一些分叉第三方应用程序并将其标准输出重定向到父进程的代码,大致如下(为简洁起见,此处没有错误处理):
char* args[] = {"/path/to/3rd/party/binary", "with", "args", NULL};
int fds[2];
pipe2(fds, O_CLOEXEC);
pid_t pid = fork();
if (pid == 0)
{
dup2(fds[1], STDOUT_FILENO);
execvp(args[0], args);
_exit(1);
}
else
{
close(fds[1]);
char buf[1024];
int bytes_read;
while ((bytes_read = read(fds[0], buf, sizeof buf - 1)) > 0)
{
buf[bytes_read] = '\0';
printf("%s", buf);
}
close(fds[0]);
waitpid(pid, NULL, 0);
}
我没有第三方应用程序的代码,它是专有的二进制文件。当在终端中使用与上述代码相同的参数运行第三方应用程序时,它最终会完成。但是,当使用上面的代码 fork 第三方二进制文件时,它并没有完成,而是变成了一个僵尸进程,上面的代码在read()
调用上挂起。
分叉的第三方二进制文件本身分叉了两个守护进程(同样,我无法控制的专有二进制文件),我认为这是造成问题的原因。分叉的守护进程将拥有复制文件描述符的副本,从而阻止read()
完成。事实上,如果dup2()
调用被替换为:
dup3(fds[1], STDOUT_FILENO, O_CLOEXEC);
子进程完成,但当然没有输出重定向到父进程。此外,当上面的代码被修改为不通过管道将任何输出重定向到父进程时,子进程会正确完成。
在这种情况下是否有可能以某种方式防止read()
呼叫挂起,或者我是否需要求助于某种形式的非阻塞 I/O?
更新; 使用简单popen()
的也有同样的问题。
(后续行动:read() 挂在僵尸进程上)
解决方案
您需要专门忽略 SIGCHLD。收割僵尸是你的责任,但在被封锁的情况下你不能这样做read
。如果你在被吞下read
后打电话,你会永远留在里面。SIGCHLD
read
推荐阅读
- javafx - 多个 Text 对象(在 JavaFX 中)可以同时设置它们的样式吗?
- macos - 无法使用终端将文件夹复制到特定位置 - Mac
- mysql - 如何将 R 连接到 MySQL?无法连接到数据库:错误:无法加载插件缓存_sha2_password
- c++ - 如何知道在这种情况下要编译什么?
- c# - 查询 System.Xml.Linq.XElement 中的元素
- python - 如何使用配置文件更改 Flask 服务器主机/端口?
- laravel - 存储在 laravel 上的奇怪问题
- ibm-doors - 传递给跳过列表的空参数
- c# - c# error cannot convert collection.generic.lists to classes
- r - 如何根据滑块输入选择过滤闪亮的日期(年份)?