简体   繁体   English

从管道读取到我的子进程

[英]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. 我会尝试按出现顺序提及它们。

  • You should check fork for the return value -1 which indicates an error (no child will have been forked in this case). 您应该检查fork的返回值-1 ,该值指示错误(在这种情况下不会分叉任何子项)。
  • All your calls to 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. 但是,您将这一价值抛弃了。 You don't need to open the pipe for reading/writing. 您无需打开管道进行读取/写入。 Pipes are suitable for that when created. 管道在创建时适用于此。
  • The child should close the ends of the pipe it does not use. 儿童应关闭不使用的管道的末端。 Add 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;
  • The 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);
  • The parent should close the ends of the pipe it does not use. 父级应关闭不使用的管道的末端。 Add 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;
  • Your main problem: You check the possibly uninitialized 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

Edit 编辑

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 . 因此,您实际上可以waitpidwaitpid的调用。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM