通过pipe道进行进程间通信

众所周知,在Linux进程间通信过程中,进程之间通过名为“Pipe”的特殊文件相互通信。

还知道对该文件执行的操作是通过一个进程写入并通过一个进程读取的,以便相互通信。

现在的问题是:

这些写入读取操作是否在通信期间并行执行(操作是并行执行的)? 如果不是,

当通信过程中的一个进程进入睡眠状态时会发生什么? 它是否为第二个进程首先执行写入操作,或者直接进入睡眠而不执行任何写入读取操作?

发送进程可以写入,直到管道缓冲区已满(Linux 2.6.11以后的64k)。 之后, 写(2)将被阻止。

接收过程将阻塞,直到数据可读取(2) 。

有关管道缓冲的更多详细信息,请参阅https://unix.stackexchange.com/a/11954

比如这个程序

#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> int main(int argc, char *argv[]) { int pipefd[2]; pid_t cpid; char wbuf[32768]; char buf[16384]; /* Initialize writer buffer with 012...89 sequence */ for (int i = 0; i < sizeof(wbuf); i++) wbuf[i] = '0' + i % 10; if (pipe(pipefd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { /* Child reads from pipe */ close(pipefd[1]); /* Close unused write end */ while (read(pipefd[0], &buf, sizeof(buf)) > 0); close(pipefd[0]); _exit(EXIT_SUCCESS); } else { /* Parent writes sequence to pipe */ close(pipefd[0]); /* Close unused read end */ for (int i = 0; i < 5; i++) write(pipefd[1], wbuf, sizeof(wbuf)); close(pipefd[1]); /* Reader will see EOF */ wait(NULL); /* Wait for child */ exit(EXIT_SUCCESS); } } 

在使用gcc pipes.c && strace -e trace=open,close,read,write,pipe,clone -f ./a.out运行时会产生以下序列gcc pipes.c && strace -e trace=open,close,read,write,pipe,clone -f ./a.out

 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 close(3) = 0 open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"..., 832) = 832 close(3) = 0 pipe([3, 4]) = 0 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f32117489d0) = 21114 close(3) = 0 write(4, "01234567890123456789012345678901"..., 32768) = 32768 write(4, "01234567890123456789012345678901"..., 32768) = 32768 write(4, "01234567890123456789012345678901"..., 32768strace: Process 21114 attached <unfinished ...> [pid 21114] close(4) = 0 [pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384 [pid 21114] read(3, <unfinished ...> [pid 21113] <... write resumed> ) = 32768 [pid 21114] <... read resumed> "45678901234567890123456789012345"..., 16384) = 16384 [pid 21113] write(4, "01234567890123456789012345678901"..., 32768 <unfinished ...> [pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384 [pid 21114] read(3, <unfinished ...> [pid 21113] <... write resumed> ) = 32768 [pid 21114] <... read resumed> "45678901234567890123456789012345"..., 16384) = 16384 [pid 21113] write(4, "01234567890123456789012345678901"..., 32768 <unfinished ...> [pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384 [pid 21114] read(3, <unfinished ...> [pid 21113] <... write resumed> ) = 32768 [pid 21114] <... read resumed> "45678901234567890123456789012345"..., 16384) = 16384 [pid 21113] close(4) = 0 [pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384 [pid 21114] read(3, "45678901234567890123456789012345"..., 16384) = 16384 [pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384 [pid 21114] read(3, "45678901234567890123456789012345"..., 16384) = 16384 [pid 21114] read(3, "", 16384) = 0 [pid 21114] close(3) = 0 [pid 21114] +++ exited with 0 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21114, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 0 +++ 

您会注意到读取和写入是交错的,并且由于管道已满或读取的数据不够,写入和读取过程将会阻塞几次。