linux 5种IO模型总结
2021/12/5 7:20:59
本文主要是介绍linux 5种IO模型总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
linux中一切皆文件,文件皆可读写,读写即IO. 因此IO在linux中绝对是一个重要的角色。
针对IO是否是同步/异步,阻塞/非阻塞,以及IO复用等,以下是5种IO模型的总结
1、同步阻塞式IO
这个最好理解:
我们举个读取鼠标事件的例子,如下:
首先先找到这个输入设备,以及它的设备名 ls /dev/input/ 以及 cat /proc/bus/input/devices
int main() { //the open flag could only be O_RDONLY, O_WRONLY, O_RDWR int fd = open("/dev/input/mouse0", O_RDONLY); char buf[512]; while(1) { printf(" --- begin read ---\n"); ssize_t bytes = read(fd, buf, sizeof(buf)); printf(" === end of read ===\n"); if(bytes < 0) { perror("read /dev/input/mouse0 failed\n"); } else { printf("read %d bytes.\n", bytes); for(int i = 0; i < bytes; i++) { printf("%x ", buf[i]); } printf("\n\n"); } } return 0; }
可以看到,默认的read方式是阻塞的,缓冲区中没有数据就会阻塞在read中,好在阻塞的时候会释放CPU。当有数据的时候,内核会将数据从内核空间拷贝到用户空间,并从read中返回
2、同步非阻塞式IO
这里需要借助fcntl把上述已经打开的fd设置成非阻塞的
static void sync_nonblock_io_mode(void) { //the open flag could only be O_RDONLY, O_WRONLY, O_RDWR int fd = open("/dev/input/mouse0", O_RDONLY); // set file status to non block int flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; int ret = fcntl(fd, F_SETFL, flags); if(ret == -1) { perror("fail to set fd to non block mode\n"); } char buf[512]; while(1) { printf(" --- begin read ---\n"); ssize_t bytes = read(fd, buf, sizeof(buf)); printf(" === end of read ===\n"); if(bytes < 0) { perror("read /dev/input/mouse0 failed\n"); } else { printf("read %d bytes.\n", bytes); for(int i = 0; i < bytes; i++) { printf("%x ", buf[i]); } printf("\n\n"); } sleep(1); } }
执行结果如下:
可见即使没有数据也不会阻塞住,而是返回一个错误然后继续运行,这里加了个sleep的操作,不然的话,CPU会很快被while循环占满。
3、异步IO
异步IO没有阻塞非阻塞的概念,纯纯是非阻塞的,可以按照中断来理解。
glibc提供了libaio, 是使用线程加阻塞调用模拟的,据说不咋滴。我们看下内核提供的异步IO接口。注意包含头文件<linux/aio_abi.h>
也就是说这里提供的接口时linux特有的系统调用,不是被标准C所接收,应当注意这一点。
4、信号驱动的IO
在我看来这不就是异步IO的一种吗。预先注册好回调函数,内核会通过SIGIO通知,并调用进程的回调函数
注意,这种方式不适合信号产生频繁,数据量很大的方式,因为这样内核要不断把数据复制到用户态,性能会变得较差
int g_fd = 0; void signal_handler(int sig) { char buf[512]; printf(" --- begin read ---\n"); ssize_t bytes = read(g_fd, buf, sizeof(buf)); printf(" === end of read ===\n"); if(bytes < 0) { perror("read /dev/input/mouse0 failed\n"); } else { printf("read %d bytes.\n", bytes); for(int i = 0; i < bytes; i++) { printf("%x ", buf[i]); } printf("\n\n"); } } static void signal_io_mode(void) { struct sigaction act; act.sa_flags = 0; act.sa_handler = signal_handler; sigaction(SIGIO, &act, NULL); // 监听SIGIO事件 g_fd = open("/dev/input/mouse0", O_RDONLY); //这几步设置需要注意 fcntl(g_fd, F_SETOWN, getpid()); int flags = fcntl(g_fd, F_GETFL, 0); flags |= O_NONBLOCK; flags |= O_ASYNC; fcntl(g_fd, F_SETFL, flags); while(1) { printf("do some other things...\n"); sleep(1); } } int main() { //sync_nonblock_io_mode(); signal_io_mode(); return 0; }
执行结果如下:
5、IO多路复用
这个我就不想花太多时间了,就是epoll,select这些。有空会为epoll开一个专题讲。
这篇关于linux 5种IO模型总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 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】分区向左扩容的方法