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

C++ 为什么父进程的输出被子进程阻止?,c++,fork,C++,Fork,在下面的代码中,我将进程分为父进程和子进程。在子进程中,我将c字符串argv[1]发送到要打印的父进程。然后我让子进程休眠4秒钟,然后打印“这是子进程。正在关闭\n” 在父进程中,我希望从子进程接收到字符串后,立即将其打印到标准输出 问题就出现在这里。在4秒后打印字符串“This is the child process.Closing\n”之前,不是立即在父进程中打印argv[1],而是发生以下情况: $g++-std=c++11 printchild.cpp-o printchild $。/

在下面的代码中,我将进程分为父进程和子进程。在子进程中,我将c字符串argv[1]发送到要打印的父进程。然后我让子进程休眠4秒钟,然后打印“这是子进程。正在关闭\n”

在父进程中,我希望从子进程接收到字符串后,立即将其打印到标准输出

问题就出现在这里。在4秒后打印字符串“This is the child process.Closing\n”之前,不是立即在父进程中打印argv[1],而是发生以下情况:

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

$。/printchild helloworld

1) 4秒过去了

2) 打印“这是子进程。正在关闭\n”

3) “helloworld”是印刷品

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

// 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;
  }
}
//printchild.cpp
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[]){
int-pipefd[2];
pid_t cpid;
如果(argc!=2){
fprintf(stderr,“用法:%s\n”,argv[0]);
退出(退出失败);
}
如果(管道(管道FD)=-1){
佩罗尔(“福克”);
退出(退出失败);
}
cpid=fork();
如果(cpid==0){
关闭(pipefd[0]);
文件*fpc=fdopen(pipefd[1],“wb”);
fprintf(fpc,“%s”,argv[1]);
fflush(fpc);
std::this_thread::sleep_for(std::chrono::seconds(4));
fprintf(stdout,“这是子进程。正在关闭\n”);
返回0;
}否则如果(cpid==-1){
perror(“分叉错误”);
退出(退出失败);
}否则{
char-str[80];
关闭(pipefd[1]);
文件*fp=fdopen(pipefd[0],“rb”);
fgets(str,80,fp);
fprintf(stdout,“%s\n”,str);
返回0;
}
}

如果在刷新后立即关闭客户端中的文件,它将按预期工作:

fflush(fpc);
fclose(fpc);
输出:

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

父进程正在通过
fgets()
读取子进程的消息。它将继续阅读,直到发生以下三种情况之一:

  • 已读取足够的字节以填充缓冲区,少于一个用于字符串终止符的字节
  • 读一行新行
  • 遇到文件结尾
子级没有发送足够的字节来耗尽缓冲区,并且它也没有发送换行符,因此父级的
fgets()
不会返回,直到子级的管道末端在退出时关闭


您可以在子级中修复此问题,方法是让它在写入消息后立即用换行符终止消息或关闭流。

您的问题是
fgets
调用。 它试图完全满足您的请求,这就是阻塞的原因

如果您正在原型化一些IPC,我建议您放弃
stdio
,转而使用原始
IO
syscalls

如果替换,例如:

char buf[100];
read(pipefd[0], buf, 100);
fprintf(stdout,"%s\n",buf);
对于
fgets
部分,您将立即收到消息,因为
read
将提供所有可用信息并返回(如果在发出
read
请求时管道缓冲区中至少有1个字节),然而,
fgets
在读取所有请求的字节之前,或者在发现无法返回之前,不会后退(EOF或IO错误)

(说白了,阻塞的不是
fgets
(用户空间代码本身无法阻止)--而是
fgets
发出的另一个暂时不可满足的
read
syscall)