C fork() 和 pipe():进程卡在读取管道中?
C fork() and pipe(): process get stuck reading pipe?
我正在练习 fork() 和管道,我有一个问题:如果我不关闭第一个管道(第一个子进程 - 第二个子进程),为什么第二个子进程会卡住读取管道父进程?
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
void checkArgs(int n){
if(n!=1){
perror("Wrong parameters number");
exit(-1);
}
}
int isAConsonant(char c){
char vowels[5]={'a','e','i','o','u'};
int i=0,toRet=1;
for(i=0;i<5 && toRet;i++){
if(c==vowels[i]){
toRet=0;
}
}
return toRet;
}
int main(int argc,char** argv){
checkArgs(argc-1);
int pipe1[2],pipe2[2],sync[2];
int pid1,pid2;
if(pipe(pipe1)<0 || pipe(pipe2)<0 || pipe(sync)<0){
perror("Error opening pipes");
exit(-1);
}
if((pid1=fork())<0){
perror("error during fork");
exit(-1);
}
if(pid1==0){ //first child
close(pipe1[0]);
close(sync[0]);
char buf[3];
int fDes=open(argv[1],O_RDONLY);
if(fDes<0){
perror("Error opening file");
exit(-1);
}
write(sync[1],"N",1);
while(read(fDes,buf,3)==3){
write(sync[1],"N",1);
write(pipe1[1],buf,3);
}
write(sync[1],"S",1);
close(sync[1]);
close(fDes);
close(pipe1[1]);
}
else{
if((pid2=fork())<0){
perror("error during fork");
exit(-1);
}
if(pid2==0){ //second child
close(pipe2[0]);
close(pipe1[1]);
char buf[3];
while(read(pipe1[0],buf,3)==3){
if(isAConsonant(buf[0])){
write(pipe2[1],buf,3);
}
}
close(pipe2[1]);
close(pipe1[0]);
}
else{ //parent
close(pipe2[1]);
close(sync[1]);
//it does not work if not executed
//close(pipe1[1]);
//close(pipe1[0]);
char toStart;
read(sync[0],&toStart,1);
while(toStart!='S'){
read(sync[0],&toStart,1);
}
int fDes=open(argv[1],O_RDWR|O_APPEND,S_IRUSR|S_IWUSR);
if(fDes<0){
perror("Error opening file");
exit(-1);
}
char buf[3];
while(read(pipe2[0],buf,3)==3){
write(fDes,buf,3);
write(fDes," ",1);
}
close(pipe2[0]);
close(sync[0]);
close(fDes);
}
}
}
这些调用正确地终止了程序
close(pipe1[1]);
close(pipe1[0]);
输入文件:
abcdefghilmnopqrstuvz
在父进程中不使用 close(pipe1[0]) 和 close(pipe1[1]) 执行代码的 Strace 屏幕:
父进程的strace
execve("./pipe", ["./pipe", "inputF"], 0x7ffc458bc820 /* 54 vars */) = 0
brk(NULL) = 0x55ed3c675000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (File o directory non esistente)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=71886, ...}) = 0
mmap(NULL, 71886, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d0b895000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]>[=13=][=13=][=13=][=13=]0l[=13=][=13=][=13=][=13=][=13=]"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2000480, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b893000
mmap(NULL, 2008696, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d0b6a8000
mmap(0x7f7d0b6cd000, 1519616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f7d0b6cd000
mmap(0x7f7d0b840000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x198000) = 0x7f7d0b840000
mmap(0x7f7d0b889000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e0000) = 0x7f7d0b889000
mmap(0x7f7d0b88f000, 13944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b88f000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f7d0b894500) = 0
mprotect(0x7f7d0b889000, 12288, PROT_READ) = 0
mprotect(0x55ed3a7d0000, 4096, PROT_READ) = 0
mprotect(0x7f7d0b8d1000, 4096, PROT_READ) = 0
munmap(0x7f7d0b895000, 71886) = 0
pipe([3, 4]) = 0
pipe([5, 6]) = 0
pipe([7, 8]) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11194
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11195
close(6) = 0
close(8) = 0
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "S", 1) = 1
openat(AT_FDCWD, "inputF", O_RDWR|O_APPEND) = 6
read(5, "def", 3) = 3
write(6, "def", 3) = 3
write(6, " ", 1) = 1
read(5, "ghi", 3) = 3
write(6, "ghi", 3) = 3
write(6, " ", 1) = 1
read(5, "lmn", 3) = 3
write(6, "lmn", 3) = 3
write(6, " ", 1) = 1
read(5, "rst", 3) = 3
write(6, "rst", 3) = 3
write(6, " ", 1) = 1
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11194, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
第一个子进程的 strace
execve("./pipe", ["./pipe", "inputF"], 0x7ffc458bc820 /* 54 vars */) = 0
brk(NULL) = 0x55ed3c675000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (File o directory non esistente)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=71886, ...}) = 0
mmap(NULL, 71886, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d0b895000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=]>[=14=][=14=][=14=][=14=]0l[=14=][=14=][=14=][=14=][=14=]"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2000480, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b893000
mmap(NULL, 2008696, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d0b6a8000
mmap(0x7f7d0b6cd000, 1519616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f7d0b6cd000
mmap(0x7f7d0b840000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x198000) = 0x7f7d0b840000
mmap(0x7f7d0b889000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e0000) = 0x7f7d0b889000
mmap(0x7f7d0b88f000, 13944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b88f000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f7d0b894500) = 0
mprotect(0x7f7d0b889000, 12288, PROT_READ) = 0
mprotect(0x55ed3a7d0000, 4096, PROT_READ) = 0
mprotect(0x7f7d0b8d1000, 4096, PROT_READ) = 0
munmap(0x7f7d0b895000, 71886) = 0
pipe([3, 4]) = 0
pipe([5, 6]) = 0
pipe([7, 8]) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11194
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11195
close(6) = 0
close(8) = 0
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "S", 1) = 1
openat(AT_FDCWD, "inputF", O_RDWR|O_APPEND) = 6
read(5, "def", 3) = 3
write(6, "def", 3) = 3
write(6, " ", 1) = 1
read(5, "ghi", 3) = 3
write(6, "ghi", 3) = 3
write(6, " ", 1) = 1
read(5, "lmn", 3) = 3
write(6, "lmn", 3) = 3
write(6, " ", 1) = 1
read(5, "rst", 3) = 3
write(6, "rst", 3) = 3
write(6, " ", 1) = 1
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11194, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ ^C
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ ls
es es.c inputF pipe pipe.c trace.11193 trace.11194 trace.11195
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ cat trace.11194
close(3) = 0
close(7) = 0
openat(AT_FDCWD, "inputF", O_RDONLY) = 3
write(8, "N", 1) = 1
read(3, "abc", 3) = 3
write(8, "N", 1) = 1
write(4, "abc", 3) = 3
read(3, "def", 3) = 3
write(8, "N", 1) = 1
write(4, "def", 3) = 3
read(3, "ghi", 3) = 3
write(8, "N", 1) = 1
write(4, "ghi", 3) = 3
read(3, "lmn", 3) = 3
write(8, "N", 1) = 1
write(4, "lmn", 3) = 3
read(3, "opq", 3) = 3
write(8, "N", 1) = 1
write(4, "opq", 3) = 3
read(3, "rst", 3) = 3
write(8, "N", 1) = 1
write(4, "rst", 3) = 3
read(3, "uvz", 3) = 3
write(8, "N", 1) = 1
write(4, "uvz", 3) = 3
read(3, "", 3) = 0
write(8, "S", 1) = 1
close(8) = 0
close(3) = 0
close(4) = 0
exit_group(0) = ?
+++ exited with 0 +++
第二个子进程的strace
close(5) = 0
close(4) = 0
read(3, "abc", 3) = 3
read(3, "def", 3) = 3
write(6, "def", 3) = 3
read(3, "ghi", 3) = 3
write(6, "ghi", 3) = 3
read(3, "lmn", 3) = 3
write(6, "lmn", 3) = 3
read(3, "opq", 3) = 3
read(3, "rst", 3) = 3
write(6, "rst", 3) = 3
read(3, "uvz", 3) = 3
read(3, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
why does the second child process get stuck reading the pipe if I don't close the first pipe (first child - second child) in the parent process?
一眼看去我不能完全理解你的代码到底做了什么,但本质上,你先创建了三个管道,然后分叉了两次。
这给您留下了三个进程和三个管道。您的每个进程作为每个管道的读取和写入端。
管道的读取端仅在所有写入器关闭时才发出 EOF 信号。我想在你的情况下这不是真的。
当有任何进程打开了管道的写入描述符时,系统不会在管道的读取描述符上报告 EOF。这包括当前流程。您必须确保管道已关闭 — 多次关闭。
经验法则:如果你
dup2()
管道的一端连接到标准输入或标准输出,同时关闭
返回的原始文件描述符
pipe()
尽早。
特别是,您应该在使用任何
exec*()
函数族。
如果您使用以下任一方式复制描述符,则该规则也适用
dup()
或者
fcntl()
F_DUPFD
如果 parent 进程将不与其任何 children 通过
管道,它必须确保尽早关闭管道的两端
足够(例如,在等待之前)以便其 children 可以接收
EOF 指示读取(或获取 SIGPIPE 信号或写入错误
写),而不是无限期地阻塞。
即使 parent 使用管道而不使用 dup2()
,它也应该
通常至少关闭管道的一端——这种情况极为罕见
在单个管道的两端读写的程序。
请注意 O_CLOEXEC
选项
open()
,
并且 fcntl()
的 FD_CLOEXEC
和 F_DUPFD_CLOEXEC
选项也可以考虑因素
进入这个讨论。
如果你使用
posix_spawn()
及其广泛的支持功能系列(总共 21 个功能),
您将需要查看如何在生成的进程中关闭文件描述符
(posix_spawn_file_actions_addclose()
,
等)。
请注意,出于多种原因,使用 dup2(a, b)
比使用 close(b); dup(a);
更安全。
一个是如果你想强制文件描述符大于
通常的数字,dup2()
是唯一明智的方法。
另一个是如果 a
与 b
相同(例如两者都是 0
),则 dup2()
正确处理它(它在复制 a
之前不会关闭 b
)
而单独的 close()
和 dup()
则失败得很厉害。
这种情况不太可能,但并非不可能。
我正在练习 fork() 和管道,我有一个问题:如果我不关闭第一个管道(第一个子进程 - 第二个子进程),为什么第二个子进程会卡住读取管道父进程?
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
void checkArgs(int n){
if(n!=1){
perror("Wrong parameters number");
exit(-1);
}
}
int isAConsonant(char c){
char vowels[5]={'a','e','i','o','u'};
int i=0,toRet=1;
for(i=0;i<5 && toRet;i++){
if(c==vowels[i]){
toRet=0;
}
}
return toRet;
}
int main(int argc,char** argv){
checkArgs(argc-1);
int pipe1[2],pipe2[2],sync[2];
int pid1,pid2;
if(pipe(pipe1)<0 || pipe(pipe2)<0 || pipe(sync)<0){
perror("Error opening pipes");
exit(-1);
}
if((pid1=fork())<0){
perror("error during fork");
exit(-1);
}
if(pid1==0){ //first child
close(pipe1[0]);
close(sync[0]);
char buf[3];
int fDes=open(argv[1],O_RDONLY);
if(fDes<0){
perror("Error opening file");
exit(-1);
}
write(sync[1],"N",1);
while(read(fDes,buf,3)==3){
write(sync[1],"N",1);
write(pipe1[1],buf,3);
}
write(sync[1],"S",1);
close(sync[1]);
close(fDes);
close(pipe1[1]);
}
else{
if((pid2=fork())<0){
perror("error during fork");
exit(-1);
}
if(pid2==0){ //second child
close(pipe2[0]);
close(pipe1[1]);
char buf[3];
while(read(pipe1[0],buf,3)==3){
if(isAConsonant(buf[0])){
write(pipe2[1],buf,3);
}
}
close(pipe2[1]);
close(pipe1[0]);
}
else{ //parent
close(pipe2[1]);
close(sync[1]);
//it does not work if not executed
//close(pipe1[1]);
//close(pipe1[0]);
char toStart;
read(sync[0],&toStart,1);
while(toStart!='S'){
read(sync[0],&toStart,1);
}
int fDes=open(argv[1],O_RDWR|O_APPEND,S_IRUSR|S_IWUSR);
if(fDes<0){
perror("Error opening file");
exit(-1);
}
char buf[3];
while(read(pipe2[0],buf,3)==3){
write(fDes,buf,3);
write(fDes," ",1);
}
close(pipe2[0]);
close(sync[0]);
close(fDes);
}
}
}
这些调用正确地终止了程序
close(pipe1[1]);
close(pipe1[0]);
输入文件:
abcdefghilmnopqrstuvz
在父进程中不使用 close(pipe1[0]) 和 close(pipe1[1]) 执行代码的 Strace 屏幕:
父进程的strace
execve("./pipe", ["./pipe", "inputF"], 0x7ffc458bc820 /* 54 vars */) = 0
brk(NULL) = 0x55ed3c675000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (File o directory non esistente)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=71886, ...}) = 0
mmap(NULL, 71886, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d0b895000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]>[=13=][=13=][=13=][=13=]0l[=13=][=13=][=13=][=13=][=13=]"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2000480, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b893000
mmap(NULL, 2008696, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d0b6a8000
mmap(0x7f7d0b6cd000, 1519616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f7d0b6cd000
mmap(0x7f7d0b840000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x198000) = 0x7f7d0b840000
mmap(0x7f7d0b889000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e0000) = 0x7f7d0b889000
mmap(0x7f7d0b88f000, 13944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b88f000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f7d0b894500) = 0
mprotect(0x7f7d0b889000, 12288, PROT_READ) = 0
mprotect(0x55ed3a7d0000, 4096, PROT_READ) = 0
mprotect(0x7f7d0b8d1000, 4096, PROT_READ) = 0
munmap(0x7f7d0b895000, 71886) = 0
pipe([3, 4]) = 0
pipe([5, 6]) = 0
pipe([7, 8]) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11194
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11195
close(6) = 0
close(8) = 0
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "S", 1) = 1
openat(AT_FDCWD, "inputF", O_RDWR|O_APPEND) = 6
read(5, "def", 3) = 3
write(6, "def", 3) = 3
write(6, " ", 1) = 1
read(5, "ghi", 3) = 3
write(6, "ghi", 3) = 3
write(6, " ", 1) = 1
read(5, "lmn", 3) = 3
write(6, "lmn", 3) = 3
write(6, " ", 1) = 1
read(5, "rst", 3) = 3
write(6, "rst", 3) = 3
write(6, " ", 1) = 1
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11194, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
第一个子进程的 strace
execve("./pipe", ["./pipe", "inputF"], 0x7ffc458bc820 /* 54 vars */) = 0
brk(NULL) = 0x55ed3c675000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (File o directory non esistente)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=71886, ...}) = 0
mmap(NULL, 71886, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d0b895000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=]>[=14=][=14=][=14=][=14=]0l[=14=][=14=][=14=][=14=][=14=]"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2000480, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b893000
mmap(NULL, 2008696, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d0b6a8000
mmap(0x7f7d0b6cd000, 1519616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f7d0b6cd000
mmap(0x7f7d0b840000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x198000) = 0x7f7d0b840000
mmap(0x7f7d0b889000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e0000) = 0x7f7d0b889000
mmap(0x7f7d0b88f000, 13944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b88f000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f7d0b894500) = 0
mprotect(0x7f7d0b889000, 12288, PROT_READ) = 0
mprotect(0x55ed3a7d0000, 4096, PROT_READ) = 0
mprotect(0x7f7d0b8d1000, 4096, PROT_READ) = 0
munmap(0x7f7d0b895000, 71886) = 0
pipe([3, 4]) = 0
pipe([5, 6]) = 0
pipe([7, 8]) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11194
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11195
close(6) = 0
close(8) = 0
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "S", 1) = 1
openat(AT_FDCWD, "inputF", O_RDWR|O_APPEND) = 6
read(5, "def", 3) = 3
write(6, "def", 3) = 3
write(6, " ", 1) = 1
read(5, "ghi", 3) = 3
write(6, "ghi", 3) = 3
write(6, " ", 1) = 1
read(5, "lmn", 3) = 3
write(6, "lmn", 3) = 3
write(6, " ", 1) = 1
read(5, "rst", 3) = 3
write(6, "rst", 3) = 3
write(6, " ", 1) = 1
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11194, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ ^C
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ ls
es es.c inputF pipe pipe.c trace.11193 trace.11194 trace.11195
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ cat trace.11194
close(3) = 0
close(7) = 0
openat(AT_FDCWD, "inputF", O_RDONLY) = 3
write(8, "N", 1) = 1
read(3, "abc", 3) = 3
write(8, "N", 1) = 1
write(4, "abc", 3) = 3
read(3, "def", 3) = 3
write(8, "N", 1) = 1
write(4, "def", 3) = 3
read(3, "ghi", 3) = 3
write(8, "N", 1) = 1
write(4, "ghi", 3) = 3
read(3, "lmn", 3) = 3
write(8, "N", 1) = 1
write(4, "lmn", 3) = 3
read(3, "opq", 3) = 3
write(8, "N", 1) = 1
write(4, "opq", 3) = 3
read(3, "rst", 3) = 3
write(8, "N", 1) = 1
write(4, "rst", 3) = 3
read(3, "uvz", 3) = 3
write(8, "N", 1) = 1
write(4, "uvz", 3) = 3
read(3, "", 3) = 0
write(8, "S", 1) = 1
close(8) = 0
close(3) = 0
close(4) = 0
exit_group(0) = ?
+++ exited with 0 +++
第二个子进程的strace
close(5) = 0
close(4) = 0
read(3, "abc", 3) = 3
read(3, "def", 3) = 3
write(6, "def", 3) = 3
read(3, "ghi", 3) = 3
write(6, "ghi", 3) = 3
read(3, "lmn", 3) = 3
write(6, "lmn", 3) = 3
read(3, "opq", 3) = 3
read(3, "rst", 3) = 3
write(6, "rst", 3) = 3
read(3, "uvz", 3) = 3
read(3, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
why does the second child process get stuck reading the pipe if I don't close the first pipe (first child - second child) in the parent process?
一眼看去我不能完全理解你的代码到底做了什么,但本质上,你先创建了三个管道,然后分叉了两次。
这给您留下了三个进程和三个管道。您的每个进程作为每个管道的读取和写入端。
管道的读取端仅在所有写入器关闭时才发出 EOF 信号。我想在你的情况下这不是真的。
当有任何进程打开了管道的写入描述符时,系统不会在管道的读取描述符上报告 EOF。这包括当前流程。您必须确保管道已关闭 — 多次关闭。
经验法则:如果你
dup2()
管道的一端连接到标准输入或标准输出,同时关闭
返回的原始文件描述符
pipe()
尽早。
特别是,您应该在使用任何
exec*()
函数族。
如果您使用以下任一方式复制描述符,则该规则也适用
dup()
或者
fcntl()
F_DUPFD
如果 parent 进程将不与其任何 children 通过
管道,它必须确保尽早关闭管道的两端
足够(例如,在等待之前)以便其 children 可以接收
EOF 指示读取(或获取 SIGPIPE 信号或写入错误
写),而不是无限期地阻塞。
即使 parent 使用管道而不使用 dup2()
,它也应该
通常至少关闭管道的一端——这种情况极为罕见
在单个管道的两端读写的程序。
请注意 O_CLOEXEC
选项
open()
,
并且 fcntl()
的 FD_CLOEXEC
和 F_DUPFD_CLOEXEC
选项也可以考虑因素
进入这个讨论。
如果你使用
posix_spawn()
及其广泛的支持功能系列(总共 21 个功能),
您将需要查看如何在生成的进程中关闭文件描述符
(posix_spawn_file_actions_addclose()
,
等)。
请注意,出于多种原因,使用 dup2(a, b)
比使用 close(b); dup(a);
更安全。
一个是如果你想强制文件描述符大于
通常的数字,dup2()
是唯一明智的方法。
另一个是如果 a
与 b
相同(例如两者都是 0
),则 dup2()
正确处理它(它在复制 a
之前不会关闭 b
)
而单独的 close()
和 dup()
则失败得很厉害。
这种情况不太可能,但并非不可能。