[英]Reading from a pipe to my child process
Hopefully a simple question. 希望是一个简单的问题。 I'm trying to learn, simultaneously, fork(), pipe(), and waitpid() and running into some problems.
我试图同时学习fork(),pipe()和waitpid()并遇到一些问题。
if (pipe(myout)<0 || pipe(myin)<0 || pipe(myerr)<0) { perror("Couldn't make pipes"); return; }
int childpid=fork();
if (childpid==0) { //child
fdopen(myout[1], "w");
fdopen(myin[1], "r");
fdopen(myerr[1], "w");
dup2(myout[1], 1);
dup2(myin[1], 0);
dup2(myerr[1], 2);
printf("This should be seen\n");
fclose(stdout); fclose(stdin); fclose(stderr);
sleep(10);
_exit(0);
} else { //parent, wait on child
printf("parent, monitoring\n");
sim_out=fdopen(myout[0], "r");
sim_in=fdopen(myin[0], "w");
sim_err=fdopen(myerr[0], "r");
printf("have my fds\n");
int status;
do {
int ch;
if (read(myout[0], &ch, 1)>0)
write(1, &ch, 1);
else printf("no go\n");
waitpid(childpid, &status, WNOHANG);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
I'm getting: 我越来越:
parent, monitoring have my fds T
父母,监控我的FDS T
before the program exits - that is, the loop runs only once. 在程序退出之前-也就是说,循环仅运行一次。 I have a check below that, and it's coming up WIFEXITED() so the process is supposed to have exited normally.
我在下面有一个检查,它即将出现WIFEXITED(),因此该进程应该正常退出了。 But what bothers me is that there's a sleep(10) before that happens, and this happens immediately - not to mention that the child processes are left running for the remaining wait time.
但是令我困扰的是,在此之前有一个sleep(10),并且这种情况立即发生-更不用说在剩余的等待时间内子进程仍在运行。
I'm fundamentally misunderstanding something, clearly. 显然,我从根本上误解了某些东西。 My expectation was that the parent loop would block until it sees a character from the child, read it, then check to see if it was still alive.
我的期望是,父循环将一直阻塞,直到看到孩子的一个字符,然后读取它,然后检查它是否仍然存在。 I certainly didn't expect waitpid() to set WIFEXITED when the child was still alive.
我当然没想到当孩子还活着的时候,waitpid()会设置为WIFEXITED。
Where am I wrong? 我哪里错了?
I think I can see several issues. 我想我可以看到几个问题。 I'll try to mention them in order of appearance.
我会尝试按出现顺序提及它们。
fork
for the return value -1
which indicates an error (no child will have been forked in this case). fork
的返回值-1
,该值指示错误(在这种情况下不会分叉任何子项)。 fdopen
leak resources (depending on the implementation; the one on RHEL4 leaks). fdopen
所有调用fdopen
泄漏资源(取决于实现;有关RHEL4的调用)。 They return a FILE*
which you could then use in fwrite
etc. and then close by doing fclose
on them. FILE*
,您可以在fwrite
等中使用它,然后对它们执行fclose
来关闭。 But you throw that value away. close (myin [1]); myin [1] = -1; close (myout [0]); myout [0] = -1; close (myerr [0]); myerr [0] = -1;
close (myin [1]); myin [1] = -1; close (myout [0]); myout [0] = -1; close (myerr [0]); myerr [0] = -1;
close (myin [1]); myin [1] = -1; close (myout [0]); myout [0] = -1; close (myerr [0]); myerr [0] = -1;
dup2
are technically fine on all Linux variants I know, but it is customary to use the first fd of a pipe for reading and the other for writing. dup2
在我所知道的所有Linux变体上在技术上都不错,但是习惯上将管道的第一个fd用于读取,将另一个fd用于写入。 Thus, your dup2
s would be best changed to dup2 (myin [0], STDIN_FILENO); dup2 (myout [1], STDOUT_FILENO); dup2 (myerr [1], STDERR_FILENO);
dup2
更改为dup2 (myin [0], STDIN_FILENO); dup2 (myout [1], STDOUT_FILENO); dup2 (myerr [1], STDERR_FILENO);
dup2 (myin [0], STDIN_FILENO); dup2 (myout [1], STDOUT_FILENO); dup2 (myerr [1], STDERR_FILENO);
close (myin [0]); myin [0] = -1; close (myout [1]); myout [1] = -1; close (myerr [1]); myerr [1] = -1;
close (myin [0]); myin [0] = -1; close (myout [1]); myout [1] = -1; close (myerr [1]); myerr [1] = -1;
close (myin [0]); myin [0] = -1; close (myout [1]); myout [1] = -1; close (myerr [1]); myerr [1] = -1;
status
for your child's exit code. status
。 But waitpid
has not yet been called. waitpid
。 You should check waitpid
's exit code and not evaluate status
if it returns something other than childpid
. waitpid
的退出代码,如果返回的不是childpid
,则不要评估status
。 Since only the pipe ends that you actually need are open now, the operating system will detect a broken pipe for you. 由于现在仅打开了您实际需要的管道末端,因此操作系统将为您检测到破裂的管道。 The pipe breaks when the child does
fclose (stdout)
. 当孩子确实关闭
fclose (stdout)
时,管道中断。 The parent can still proceed to read all the data that may be in the pipe, but after that read
will return zero, indicating a broken pipe. 父级仍然可以继续读取管道中可能存在的所有数据,但是
read
将返回零,表示管道已损坏。
Thus, you can actually spare the call to waitpid
. 因此,您实际上可以
waitpid
对waitpid
的调用。 You could instead simply wait for read
to return zero. 相反,您可以简单地等待
read
返回零。 This is not 100% equivalent, though, since your child closes its end of the pipe before it goes to sleep
(causing the parent to proceed when all data have been read), whereas the waitpid
version, of course, only proceeds when the child actually died. 但是,这并不是100%等效的,因为您的孩子在进入
sleep
之前关闭了管道的末端(导致在读取所有数据后父级继续进行操作),而waitpid
版本当然仅在孩子进入sleep
时进行真的死了
Somebody answered this... I don't know what happened to it. 有人回答了...我不知道发生了什么。 Considering I'm a newbie here, maybe I deleted it somehow?
考虑到我是这里的新手,也许我以某种方式删除了它? If so, I apologize, but they had the answer.
如果是这样,我表示歉意,但他们有答案。
The solution is to not use the WIF* macros unless waitpid()>0, since apparently otherwise the 0 is considered a normal exit. 解决方案是除非waitpid()> 0,否则不要使用WIF *宏,因为显然否则0被认为是正常出口。 I inserted a check into my code and it now works - thanks everyone for the editing pointers.
我在代码中插入了一张支票,现在可以使用-感谢大家的编辑指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.