希望是一个简单的问题。我正在尝试同时学习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));
}
我得到了:
父母,监督 有我的fds Ť在程序退出之前
- 也就是说,循环只运行一次。我在下面有一张支票,它正在WIFEXITED(),所以这个过程应该正常退出。但困扰我的是,在发生这种情况之前会有一个睡眠(10),这会立即发生 - 更不用说子进程在剩余的等待时间内保持运行。
显然,我从根本上误解了一些事情。我的期望是父循环会阻塞,直到它看到孩子的一个角色,读取它,然后检查它是否还活着。我当然不希望waitpid()在孩子还活着的时候设置WIFEXITED。
我哪里错了?
答案 0 :(得分:5)
我想我可以看到几个问题。我会尝试按照出现的顺序提及它们。
fork
是否有返回值-1
,表示错误(在这种情况下不会分叉孩子)。fdopen
的所有调用都会泄漏资源(具体取决于实现; RHEL4上的泄漏)。他们返回FILE*
,然后您可以在fwrite
等中使用,然后在fclose
上关闭它们。但是你抛弃了这个价值。您无需打开管道进行读/写操作。管道在创建时适合。close (myin [1]); myin [1] = -1; close (myout [0]); myout [0] = -1; close (myerr [0]); myerr [0] = -1;
dup2
在我所知道的所有Linux变体上技术上都很好,但习惯上使用管道的第一个fd进行读取而另一个用于写入。因此,您的dup2
最好更改为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;
status
。但waitpid
尚未被调用。您应该检查waitpid
的退出代码,如果返回的内容不是status
,则不评估childpid
。由于现在只打开您实际需要的管道末端,操作系统会为您检测到管道损坏。当孩子fclose (stdout)
时,管道会断裂。父级仍然可以继续读取管道中可能存在的所有数据,但在此之后read
将返回零,表示管道已损坏。
因此,您实际上可以将呼叫转移到waitpid
。您只需等待read
返回零即可。但是,这不是100%等效,因为您的孩子在进入sleep
之前关闭管道的末尾(导致父项在读取所有数据后继续),而waitpid
版本,当然,只有当孩子真正死去时才会收获。
答案 1 :(得分:0)
有人回答了这个问题......我不知道发生了什么事。考虑到我在这里是新手,也许我以某种方式删除了它?如果是这样,我道歉,但他们有答案。
解决方案是不使用WIF *宏,除非waitpid()> 0,因为显然否则0被认为是正常退出。我在我的代码中插入了一张支票,它现在可以运行了 - 感谢所有人编辑指针。