简体   繁体   English

为什么父进程的输出被子进程阻止?

[英]Why is output of parent process blocked by child process?

In my code below, I forked my process into a parent and child process. 在下面的代码中,我将进程分叉为父进程和子进程。 In the child process, I sent the c string argv[1] to the parent process to be printed. 在子进程中,我将c字符串argv [1]发送到父进程进行打印。 Then I made the child process sleep for 4 seconds before printing "This is the child process. Closing\\n". 然后,我让子进程休眠4秒钟,然后打印“这是子进程。正在关闭\\ n”。

In the parent process, I want the string from the child process to be printed to stdout as soon as I receive it from the child process. 在父进程中,我希望从子进程收到的字符串立即将其打印到stdout。

The problem arises here. 问题出现在这里。 Instead of immediately printing argv[1] in the parent process before the string "This is the child process. Closing\\n" is printed 4 seconds later, what happens is this: 而不是立即在字符串“ This is child process。Closing \\ n”显示在4秒后在父进程中立即打印argv [1]的情况是:

$ g++ -std=c++11 printchild.cpp -o printchild $ g ++ -std = c ++ 11 printchild.cpp -o printchild

$ ./printchild helloworld $ ./printchild helloworld

1) 4 seconds passes 1)4秒过去

2) "This is the child process. Closing\\n" is printed 2)打印“这是子进程。关闭\\ n”

3) "helloworld" is printed 3)打印“ helloworld”

Why is the output from the parent process blocked by the child process? 为什么父进程的输出被子进程阻止?

// printchild.cpp
#include <chrono>
#include <thread>
#include <cstdio>
#include <unistd.h>
#include <cstdlib>

int main(int argc, char * argv[]){
  int pipefd[2];
  pid_t cpid;
  if(argc != 2){
    fprintf(stderr, "Usage: %s <string>\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  if(pipe(pipefd) == -1){
    perror("fork");
    exit(EXIT_FAILURE);
  }
  cpid = fork();
  if(cpid == 0){
    close(pipefd[0]);
    FILE *fpc = fdopen(pipefd[1],"wb");
    fprintf(fpc,"%s",argv[1]);
    fflush(fpc);
    std::this_thread::sleep_for(std::chrono::seconds(4));
    fprintf(stdout,"This is the child process. Closing\n");
    return 0;
  }else if(cpid == -1){
    perror("Error in forking");
    exit(EXIT_FAILURE);
  }else{
    char str[80];
    close(pipefd[1]);
    FILE* fp = fdopen(pipefd[0], "rb");
    fgets(str,80,fp);
    fprintf(stdout,"%s\n",str);
    return 0;
  }
}

The parent process is reading the child's message via fgets() . 父进程正在通过fgets()阅读孩子的消息。 It will continue to read until one of three things happens: 它将继续读取,直到发生以下三种情况之一:

  • enough bytes have been read to fill the buffer, less one for a string terminator 读取了足够的字节以填充缓冲区,对于字符串终止符,则减少了一个字节
  • a newline is read 换行符被读取
  • end-of-file is encountered 遇到文件结尾

The child does not send enough bytes to exhaust the buffer, and it does not send a newline, so the parent's fgets() does not return until the child's end of the pipe is closed upon its exit. 子级不会发送足够的字节来耗尽缓冲区,它也不会发送换行符,因此父级的fgets()不会返回,直到子级的管道末端在退出时关闭为止。

You can fix this in the child by having it either terminate the message with a newline or close the stream immediately after writing. 您可以通过让子进程以换行符终止消息或在写完后立即关闭流来解决此问题。

If you close the file in the client right after flushing, it will work as expected: 如果在刷新后立即在客户端中关闭文件,它将按预期工作:

fflush(fpc);
fclose(fpc);

Output: 输出:

[dbush] /tmp/x1 hello
hello
[dbush] This is the child process. Closing

Your problem is the fgets call. 您的问题是fgets调用。 It tries to fulfill your request fully, and that's the cause of the blocking. 它会尝试完全满足您的要求,这就是阻塞的原因。

If you're prototyping some IPC, I recommend you ditch stdio and go for the raw IO syscalls. 如果您要制作一些IPC的原型,我建议您放弃stdio并进行原始的IO系统调用。

If you substitute, eg: 如果替代,例如:

char buf[100];
read(pipefd[0], buf, 100);
fprintf(stdout,"%s\n",buf);

for the fgets part, you'll get your message right away, because read will give you whatever's available and return (if there's at least 1 byte in the pipe buffer at the time you make the read request), whereas fgets won't back off until it has read all the requested bytes or until it figures out it can't (EOF or an IO error). 对于fgets部分,您将立即收到消息,因为read会为您提供可用的内容并返回(如果在发出read请求时管道缓冲区中至少有1个字节),而fgets不会返回直到读完所有请求的字节或发现无法读取为止(EOF或IO错误)。

(To split hairs, it's not fgets that's blocking (userspace code alone can't block) -- it's another momentarily unsatisfiable read syscall that fgets has issued). (要乱发,不是fgets阻塞了(仅用户空间代码无法阻塞)-这是fgets发出的另一个暂时无法满足的read syscall)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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