笔记地址:https://note.youdao.com/ynoteshare1/index.html?id=09f9fa91b90576adac4640f48b9210a3&type=note
前面第一节我们学习了对IO的open、read、write等阻塞式文件操作,这一篇我们将会学习对IO的一些高级操作。 2019/04/30 20:51
目录
一、非阻塞IO的引入
1、阻塞与非阻塞
- a) 函数操作文件时,因文件类型而阻塞,阻塞与函数本身无关
·读某些文件:由于数据不存在会导致调用者永远阻塞
读管道文件:管道是进程间通信用的特殊文件,读管道时,如果管道中并无数据会导致
对管道的读操作会阻塞。
- b) 写某些文件:在写某些文件时,当文件不能立即接收写入的数据时,也可能会导致
- c) 某些函数本身就是阻塞的
wait、pause、sleep等函数以及某些进程间通信的函数(如当消息队列的消息接受函数设置了阻塞时),这些函数调用本身就是阻塞的
2、如何修改阻塞为非阻塞
通过前面的学习,我们知道某些文件默认打开后默认对文件的操作就是阻塞的,但是利用对文件描述符设置,可将其操作设置为非阻塞的,主要的方法有如下两种:
- 1)打开文件时指定非阻塞,以非阻塞的方式打开标准输入文件(O_NONBLOCK函数,指定为了非阻塞)
int main(void){ int fd = -1; fd = open("/dev/stdin", O_RDONLY|O_NONBLOCK); if(fd < 0){ perror("open stdin is fail"); exit(-1); } return 0; } |
- 2)将已经打开了的文件描述符设置为非阻塞的
(用fcntl函数进行设置,具体可查看第一节对fcntl函数的梳理)
int main(void) { int fd = -1, flag = -1; /* F_GETFL:获取描述符原有状态给flag的命令,目的是为了保护原有的状态 * STDIN_FILENO:指向标准输入文件的文件描述符0 */ flag = fcntl(STDIN_FILENO, F_GETFL); flag |= O_NONBLOCK;//将原有文件状态 | 非阻塞标志 //将修改后的包含了非阻塞标志的新状态重新设置回去 fcntl(STDIN_FILENO, F_SETFL, flag); return 0; } |
二.阻塞式IO的困境(举例)
1、程序中读取键盘
int main(void) { // 读取键盘 // 键盘就是标准输入,故为0号文件描述符,stdin char buf[100]; memset(buf, 0, sizeof(buf)); printf("before read.\n"); read(0, buf, 5); printf("读出的内容是:[%s].\n", buf); return 0; } |
2、程序中读取鼠标
我们鼠标的驱动文件如下:当查看mouse1,移动鼠标,并没有数据,当查看mouse0时,有乱码的数据,故我们的鼠标设备文件为:mouse0
int main(void) { // 读取鼠标 int fd = -1; char buf[200]; fd = open("/dev/input/mouse0", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } memset(buf, 0, sizeof(buf)); printf("before read.\n"); read(fd, buf, 50); printf("读出的内容是:[%s].\n", buf); return 0; } |
3、程序中同时读取键盘和鼠标
int main(void) { // 读取鼠标 int fd = -1; char buf[200]; fd = open("/dev/input/mouse1", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } memset(buf, 0, sizeof(buf)); printf("before 鼠标 read.\n"); read(fd, buf, 50); printf("鼠标读出的内容是:[%s].\n", buf); // 读键盘 memset(buf, 0, sizeof(buf)); printf("before 键盘 read.\n"); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); return 0; } |
4、问题分析
(程序上设计是先读取鼠标,再读取键盘),如果顺序用反了,会怎么样???
运行程序时由于先读的是鼠标,它阻塞了键盘,所以我们先键盘敲入数据是没有用的,当移动鼠标后,鼠标数据打印