为什么父进程的输出被子进程阻塞?
Why is output of parent process blocked by child process?
在我下面的代码中,我将我的进程分叉为父进程和子进程。在子进程中,我将c字符串argv[1]发送给父进程进行打印。然后我让子进程在打印 "This is the child process. Closing\n" 之前休眠 4 秒。
在父进程中,我希望从子进程接收到的字符串立即打印到标准输出。
问题就出在这里。而不是在 4 秒后打印字符串 "This is the child process. Closing\n" 之前立即在父进程中打印 argv[1],会发生这样的事情:
$ g++ -std=c++11 printchild.cpp -o printchild
$ ./printchild helloworld
1) 4 秒过去了
2) "This is the child process. Closing\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;
}
}
如果您在刷新后立即关闭客户端中的文件,它将按预期工作:
fflush(fpc);
fclose(fpc);
输出:
[dbush] /tmp/x1 hello
hello
[dbush] This is the child process. Closing
parent 进程正在通过 fgets()
读取 child 的消息。它将继续阅读,直到发生以下三种情况之一:
- 已读取足够的字节来填充缓冲区,少了一个字符串终止符
- 读取换行符
- end-of-file遇到
child 没有发送足够的字节来耗尽缓冲区,也没有发送换行符,所以 parent 的 fgets()
没有 return直到 child 的管道末端在其出口处关闭。
您可以在 child 中解决此问题,方法是让它以换行符终止消息或在写入后立即关闭流。
您的问题是 fgets
电话。
它试图完全满足您的请求,这就是阻塞的原因。
如果您正在制作一些 IPC 的原型,我建议您放弃 stdio
并使用原始的 IO
系统调用。
如果您替换,例如:
char buf[100];
read(pipefd[0], buf, 100);
fprintf(stdout,"%s\n",buf);
对于 fgets
部分,您会立即收到消息,因为 read
会为您提供可用的任何内容,而 return(如果管道中至少有 1 个字节在您发出 read
请求时缓冲),而 fgets
不会后退,直到它读取了所有请求的字节或直到它发现它不能(EOF 或 IO 错误) .
(说实话,阻塞的不是 fgets
(仅用户空间代码无法阻塞)——这是 fgets
发出的另一个暂时无法满足的 read
系统调用)。
在我下面的代码中,我将我的进程分叉为父进程和子进程。在子进程中,我将c字符串argv[1]发送给父进程进行打印。然后我让子进程在打印 "This is the child process. Closing\n" 之前休眠 4 秒。
在父进程中,我希望从子进程接收到的字符串立即打印到标准输出。
问题就出在这里。而不是在 4 秒后打印字符串 "This is the child process. Closing\n" 之前立即在父进程中打印 argv[1],会发生这样的事情:
$ g++ -std=c++11 printchild.cpp -o printchild
$ ./printchild helloworld
1) 4 秒过去了
2) "This is the child process. Closing\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;
}
}
如果您在刷新后立即关闭客户端中的文件,它将按预期工作:
fflush(fpc);
fclose(fpc);
输出:
[dbush] /tmp/x1 hello
hello
[dbush] This is the child process. Closing
parent 进程正在通过 fgets()
读取 child 的消息。它将继续阅读,直到发生以下三种情况之一:
- 已读取足够的字节来填充缓冲区,少了一个字符串终止符
- 读取换行符
- end-of-file遇到
child 没有发送足够的字节来耗尽缓冲区,也没有发送换行符,所以 parent 的 fgets()
没有 return直到 child 的管道末端在其出口处关闭。
您可以在 child 中解决此问题,方法是让它以换行符终止消息或在写入后立即关闭流。
您的问题是 fgets
电话。
它试图完全满足您的请求,这就是阻塞的原因。
如果您正在制作一些 IPC 的原型,我建议您放弃 stdio
并使用原始的 IO
系统调用。
如果您替换,例如:
char buf[100];
read(pipefd[0], buf, 100);
fprintf(stdout,"%s\n",buf);
对于 fgets
部分,您会立即收到消息,因为 read
会为您提供可用的任何内容,而 return(如果管道中至少有 1 个字节在您发出 read
请求时缓冲),而 fgets
不会后退,直到它读取了所有请求的字节或直到它发现它不能(EOF 或 IO 错误) .
(说实话,阻塞的不是 fgets
(仅用户空间代码无法阻塞)——这是 fgets
发出的另一个暂时无法满足的 read
系统调用)。