我正在使用popen()创建管道,并且该过程正在调用第三方工具,在极少数情况下,我需要终止该工具。
::popen(thirdPartyCommand.c_str(), "w");
如果我只是抛出异常并展开堆栈,则展开尝试尝试对不再需要其结果的第三方进程调用pclose()。但是,pclose()永远不会返回,因为它在Centos 4上受到以下堆栈跟踪的阻塞:
#0 0xffffe410 in __kernel_vsyscall ()
#1 0x00807dc3 in __waitpid_nocancel () from /lib/libc.so.6
#2 0x007d0abe in _IO_proc_close@@GLIBC_2.1 () from /lib/libc.so.6
#3 0x007daf38 in _IO_new_file_close_it () from /lib/libc.so.6
#4 0x007cec6e in fclose@@GLIBC_2.1 () from /lib/libc.so.6
#5 0x007d6cfd in pclose@@GLIBC_2.1 () from /lib/libc.so.6
有什么办法可以强制在调用之前成功调用pclose(),这样我就可以以编程方式避免这种情况的发生,因为我不再向p停止提供输入,因此挂起等待pclose()成功的情况,但永远不会成功popen()处理过程并希望放弃它的工作?
在尝试关闭文件描述符之前,是否应该以某种方式将文件结尾写入popen()文件描述符?
请注意,第三方软件正在自我 fork 。在挂起pclose()的那一刻,有四个进程,其中一个已关闭:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
abc 6870 0.0 0.0 8696 972 ? S 04:39 0:00 sh -c /usr/local/bin/third_party /home/arg1 /home/arg2 2>&1
abc 6871 0.0 0.0 10172 4296 ? S 04:39 0:00 /usr/local/bin/third_party /home/arg1 /home/arg2
abc 6874 99.8 0.0 10180 1604 ? R 04:39 141:44 /usr/local/bin/third_party /home/arg1 /home/arg2
abc 6875 0.0 0.0 0 0 ? Z 04:39 0:00 [third_party] <defunct>
最佳答案
我在这里看到两个解决方案:
fork()
,pipe()
和execve()
(或exec
系列中的任何内容……),然后由您决定是否要让 child 成为僵尸。 (即是否为他们输入wait()
)sysctl()
... yuk 之前,使用pclose()
检查是否有任何使用此名称的进程在运行。 我强烈建议您采用一种简洁的方法,或者您可以问问负责修复第三方工具中无限循环的人,哈哈。
祝好运!
编辑:
关于您的第一个问题:我不知道。对如何使用
sysctl()
shoud按名称查找进程进行了一些研究,可以告诉您您需要了解的内容,我自己从来没有做过这么远的事情。对于第二个和第三个问题:
popen()
本质上是fork()
+ pipe()
+ dup2()
+ execl()
的包装。fork()
复制该过程,execl()
用一个新的替换图像,pipe()
处理过程间的通信,dup2()
用于重定向输出...然后pclose()
将wait()
删除重复的过程,这就是为什么我们在这里。如果您想了解更多,您应该检查this answer,我最近在其中解释了如何使用标准IPC执行简单的派生。在这种情况下,这有点复杂,因为您必须使用
dup2()
将标准输出重定向到管道。您还应该看看
popen()/pclose()
源代码,因为它们当然是开源的。最后,这是一个简短的示例,我不能说得更清楚:
int pipefd[2];
pipe(pipefd);
if (fork() == 0) // I'm the child
{
close(pipefd[0]); // I'm not going to read from this pipe
dup2(pipefd[1], 1); // redirect standard output to the pipe
close(pipefd[1]); // it has been duplicated, close it as we don't need it anymore
execve()/execl()/execsomething()... // execute the program you want
}
else // I'm the parent
{
close(pipefd[1]); // I'm not going to write to this pipe
while (read(pipefd[0], &buf, 1) > 0) // read while EOF
write(1, &buf, 1);
close(pipefd[1]); // cleaning
}
与往常一样,请记住阅读手册页并检查所有返回值。
再次祝你好运!