结论:
一、当管道内没有数据可读时
O_NONBLOCK disable:read 调用阻塞,直到有可读数据
O_NONBLOCK enable: read 调用返回 -1,errno 值为 EAGAIN
二、当管道已满或者剩余空间不够时
O_NONBLOCK disable:write 调用阻塞,直到有进程读走数据,管道中有足够大的可用空间
O_NONBLOCK enable: write 调用返回 -1,errno 值为 EAGAIN
匿名管道默认是阻塞模式,可通过以下示例修改为非阻塞模式
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
命名管道的阻塞模式和非阻塞模式设定参见以下示例
open("fifo", flags | O_NONBLOCK); //非阻塞
open("fifo", flags); //阻塞
三、
如果所有管道写端对应的文件描述符被关闭,则 read 调用返回 0
如果所有管道读端对应的文件描述符被关闭,则 write 调用会产生信号 SIGPIPE,进而可能导致写进程退出
四、man 7 pipe
1、当要写入的数据量n <= PIPE_BUF 时,linux 将保证写入的原子性
O_NONBLOCK disable:如果管道中有足够大的可用空间便写入;否则 write 调用阻塞,直到管道中有足够大的可用空间
O_NONBLOCK enable: 如果管道中有足够大的可用空间便写入;否则 write 调用返回 -1,errno 值为 EAGAIN
2、当要写入的数据量n > PIPE_BUF 时,linux 将不再保证写入的原子性
O_NONBLOCK disable:write 直到将所有数据写入管道后返回,期间可能有其他进程穿插写入
O_NONBLOCK enable: 如果管道已满,write 调用返回 -1,errno 值为 EAGAIN;否则实际写入的数据量为 1 ~ n,即部分写入,期间可能有其他进程穿插写入
验证如下:
1、O_NONBLOCK disable:read 调用阻塞
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>int main(void)
{int fds[2];pid_t pid;time_t t;char buf[10] = {0};if(0 != pipe(fds)){perror("pipe error");exit(EXIT_FAILURE);}pid = fork();if (-1 == pid){perror("fork error");exit(EXIT_FAILURE);}if (0 == pid){close(fds[0]); //关闭读端sleep(10);write(fds[1], "hello", 5);exit(EXIT_SUCCESS);}close(fds[1]); //关闭写端t = time(NULL);read(fds[0], buf, sizeof(buf));t = time(NULL) - t;printf("receive data: %s, interval time: %ds\n", buf, t);waitpid(pid, NULL, 0);return 0;
}
/** receive data: hello, interval time: 10s*/
2、O_NONBLOCK enable:read 调用返回 -1,errno 值为 EAGAIN(11)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>int main(void)
{int fds[2], flags;pid_t pid;char buf[10] = {0};if(0 != pipe(fds)){perror("pipe error");exit(EXIT_FAILURE);}pid = fork();if (-1 == pid){perror("fork error");exit(EXIT_FAILURE);}if (0 == pid){close(fds[0]);sleep(10);write(fds[1], "hello", 5);exit(EXIT_SUCCESS);}close(fds[1]);flags = fcntl(fds[0], F_GETFL);fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);if (-1 == read(fds[0], buf, sizeof(buf))){perror("read error");printf("errno: %d\n", errno);waitpid(pid, NULL, 0);exit(EXIT_FAILURE);}printf("receive data: %s\n", buf);waitpid(pid, NULL, 0);return 0;
}
/** read error: Resource temporarily unavailable* errno: 11*/
3、O_NONBLOCK disable:write 调用阻塞
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>int main(void)
{int fds[2];char buf[4096];int count = 0;if(0 != pipe(fds)){perror("pipe error");exit(EXIT_FAILURE);}memset(buf, 'A', sizeof(buf));while(1){count += write(fds[1], buf, sizeof(buf));printf("writed data length: %d\n", count);}return 0;
}
/*writed data length: 4096writed data length: 8192writed data length: 12288writed data length: 16384writed data length: 20480writed data length: 24576writed data length: 28672writed data length: 32768writed data length: 36864writed data length: 40960writed data length: 45056writed data length: 49152writed data length: 53248writed data length: 57344writed data length: 61440writed data length: 65536阻塞卡住*/
4、O_NONBLOCK enable: write 调用返回 -1,errno 值为 EAGAIN(11)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>int main(void)
{int fds[2], flags;char buf[4096];int ret, count = 0;if(0 != pipe(fds)){perror("pipe error");exit(EXIT_FAILURE);}flags = fcntl(fds[1], F_GETFL);fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);memset(buf, 'A', sizeof(buf));while(1){ret = write(fds[1], buf, sizeof(buf));if (-1 == ret){perror("write error");printf("errno: %d\n", errno);exit(EXIT_FAILURE);}count += ret;printf("writed data length: %d\n", count);}return 0;
}
/*writed data length: 4096writed data length: 8192writed data length: 12288writed data length: 16384writed data length: 20480writed data length: 24576writed data length: 28672writed data length: 32768writed data length: 36864writed data length: 40960writed data length: 45056writed data length: 49152writed data length: 53248writed data length: 57344writed data length: 61440writed data length: 65536write error: Resource temporarily unavailableerrno: 11*/
5、所有管道写端对应的文件描述符被关闭,read 调用返回 0
6、所有管道读端对应的文件描述符被关闭,write 调用会产生信号 SIGPIPE