Linux:匿名管道的非阻塞属性
2021/8/6 7:06:05
本文主要是介绍Linux:匿名管道的非阻塞属性,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
如何将文件描述符设置为非阻塞:
#include<fcntl.h> int fcntl(int fd, int cmd, …/*arg*/)
fcntl函数有两个功能:
- 查看属性
- 设置非阻塞属性:O_NONBLOCK
参数:
- fd:文件描述符
- cmd:告诉fcntl函数做什么事情,由两个宏去告诉
- arg:可变参数列表,在设置属性时要保留原属性
F_GETFL | 获取一个文件描述符的权限,忽略arg参数 |
---|---|
F_SETFL | 设置一个文件描述符属性,新属性在第三个参数中设置新属性 |
返回值:
- 参数如果是F_GETFL,返回文件描述符的属性。属性为0
- 参数如果是F_SETFL,返回设置0成功,返回-1设置失败
#include<stdio.h> #include<unistd.h> int main () { int fd[2];int ret=pipe(fd);//在内核中创建了一个管道 if(ret<0) { perror("pipe"); } int flag=fcntl(fd[0], F_GETFL) //查看读端属性,打印出的数值为0,这个0是属性不是保存的值 fcntl(fd[0], F_SETFL, flag | O_NONBLOCK) //设置新属性时,要保留原属性 int flag=fcntl(fd[0], F_GETFL) //再次查看f[0]的属性,数值变成2048 }
为什么读端阻塞属性为0,非阻塞属性是2048;因为文件打开方式的宏为位图的使用方式;例如在之前使用open函数,为什么能使用按位或的方式能表示既可以读写,文件不存在时又可以创建:
open(“./1.txt”, O_RDWR | O_CREAT, 0664) //0表示八进制,664是权限
操作系统内核本质上也是由代码构成的,O_RDWR ,O_CREAT这些宏在内核中是有定义的;内核源码定义:
1.
先查看fd[0]的原属性:
验证代码:
结果:
结论:
- fd[0]的属性信息是0
- 在内核源码中,O_RDONLY对应的八进制是全0,转化成十进制也是全0,所以说f[0]的是只读属性
- 我们说fd[0]是管道的读端是因为其对应的文件描述符的属性为只读属性
2.
接下来再给fd[0]添加非阻塞属性
代码:
- 在增加属性的时候一定要用
或 |
保留原属性,不保留那就是重新设置了一个新属性,之前的属性就都没有了 - 第二次的属性是2048,相对于0多了一个非阻塞属性;
- 以上验证了文件打开方式的宏,在内核中都是使用位图的方式进行计算的
匿名管道的非阻塞特性:
代码1:
#include<stdio.h> #include<unistd.h> #include<fcntl.h> int main () { //创建管道 int fd[2]; int ret=pipe(fd); //设置读文件描述符为非阻塞属性 if(ret<0) { perror("fork"); } int flag=fcntl(fd[0], F_GETFL); fcntl(fd[0], F_SETFL, flag|O_NONBLOCK); //创建父子进程,父子进程谁读谁写不影响验证结果 //规定子进程读,父进程写 pid_t pid=fork(); if(pid<0) { perror(fork); return 0; } else if(pid==0)//子进程 { char buf[1024]={0}; size_t size=read(fd[0], buf,sizeof(buf)-1); printf("size:%ld",size); } else//父进程 { close(fd[0]); sleep(1); } return 0; }
读端设置成非阻塞
只需要父进程写端,子进程读端
1.父进程写端不关闭;子进程一直读
调用read函数后,返回值为-1
- 含义1.表示未在管道中读到内容
- 含义2.表示在读管道时调用错误
- 通过错误码区分,将errno置为EAGAIN表示1成立,应循环继续读取,这就是非阻塞要搭配循环的一种体现
2.父进程写端关闭;子进程一直读
- 含义1.表示没有读到内容
- 含义2.因为没有写端而返回(该情况成立)
- 返回0后就不用搭配循环了,因为该种情况表示管道没有写端
代码2:
#include<stdio.h> #include<unistd.h> #include<fcntl.h> int main () { int fd[2]; int ret=pipe(fd); //设置读文件描述符为非阻塞属性 if(ret<0) perror("fork"); int flag=fcntl(fd[1], F_GETFL); fcntl(fd[1], F_SETFL, flag|O_NONBLOCK); pid_t pid=fork(); if(pid<0) { perror(fork); return 0; } else if(pid==0)//子进程 { close(fd[0]); int count=0; while(1) { size_t size=write(fd[1], "1", 1); if(size!=1) { printf("size:%d", size); break; } printf("count:%ld\n", ++count); } } else//父进程 { close(fd[1]); while(1) { sleep(2); } } return 0; }
写端设置成非阻塞
父进程读,子进程写
因为最后一个结果会导致一个进程崩溃,设置子进程写,父进程读
1.写端设置成非阻塞,子进程写,父进程读
- 子进程只写一次,父进程读端不关闭,正常输出
- 子进程一种写,在管道写满之后返回-1;写满管道后再次调用write函数,返回-1
2.写端设置成非阻塞,读端关闭,
- 调用写就会崩溃,产生僵尸进程
所有读端都关闭,子进程刚往管道中一些写,就收到信号,导致子进程崩溃
谁设置成非阻塞,谁就是因变量,将另一方设置成自变量(关不关闭)
这篇关于Linux:匿名管道的非阻塞属性的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南
- 2024-08-21【Linux】分区向左扩容的方法