内容: 管道其实是内存里的一块环形缓冲区,管道在使用的时候不一定都是原子性的
管道的大小:
管道的大小就是图中的pipe size: 512bytes × 8 = 4KB,
(其
中,512代表一个扇区的大小,8表示用了8个扇区,所以是4KB,大小可调节)
阻塞与非阻塞对使用管道的区别:
当没有数据可读时
O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
当管道满的时候
O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
如果所有管道写端对应的文件描述符被关闭,则read返回0
如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE
管道的写入原子性:
当要写入的数据量不大于PIPE_BUF时,linux保证写入的原子性。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。
注意:虽然ulimit -a显示管道大小为4KB,但是实际写满是需要写入65536字节满的。也就是你一次性写入
的容量大于65536字节时,原子性就得不到保障了
管道的容量与管道的缓冲区:
管道的大小用ulimit -a查询得到的是:4KB。但是为什么可以写65536个字节呢?
原因:ulimit -a查出来的管道缓冲区大小,也就是pipe_buf的大小,管道容量:pipe_capacity并不是
这么大。
pipe_buf :4KB
pipe_capacity :pipe_buf × pipe_buf的数量 = 4KB × 16 = 65536字节
pipe_buf数量可以在内核的pipe文件中看到:16个 (大家可以在自己的linux系统查pipe头文件查看)
大数据下管道原子性测试: 借用一下网上的代码修改成小数据和大数据测试
情况一:写入10KB时
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define SIZE 10*1024 //10KB
int main() {
char A[SIZE];
char B[SIZE];
memset(A, 'A', sizeof(A));
memset(B, 'B', sizeof(B));
int pipefd[2];
if(pipe(pipefd) < 0) {
perror("create pipe error\n");
return -1;
}
int ret = 0;
pid_t pid = fork();
if(pid < 0 ) {
perror("do fork error\n");
return -1;
}
else if(pid == 0) {
close(pipefd[0]);
ret = write(pipefd[1], A, sizeof(A));
printf("Child process [%d] wrote %d bytes of process_1 to the pipeline.\n", getpid(), ret);
exit(0);
}
pid = fork();
if(pid < 0 ) {
perror("fork error");
return -1;
}
else if(pid == 0) {
close(pipefd[0]);
ret = write(pipefd[1], B, sizeof(B));
printf("Child process [%d] wrote %d bytes of process_2 to the pipeline.\n", getpid(), ret);
exit(0);
}
close(pipefd[1]);
sleep(1); //休眠1s,确保父子进程的写端都已关闭
int n = 0;
while(1) {
char buf[4*1024] = {0};
ret = read(pipefd[0], buf, sizeof(buf));
if(ret == 0) {
printf("data read out.\n");
break;
}
printf("%2d: Parent process [%d] read %d bytes from the pipeline, buf[4095] = %c\n", ++n, getpid(), ret, buf[4095]);
}
return 0;
}
运行结果:此时写入是原子性的
情况二:写入100KB时
运行结果:此时写入不是原子性的
大四学生一枚,如果文章有错误的地方,欢迎在下方提出,每条评论我都会去认真看并回复,同时感谢指正的前辈。有喜欢C/C++,linux的同学欢迎私信一起讨论学习。