I/O多路复用学习(一)select
前言
本文主要是简单讨论select的特点并梳理一下select的调用链,不涉及具体的使用方法。
本文中涉及的源码均出自Linux内核5.4.0版本
简介
select 是一种 IO 多路复用的技术,它允许单个进程或线程高效地管理多个输入/输出流,从而提高程序的性能和响应速度。
调用过程
do_select
select的核心功能都在do_select中,里面的关键操作有:
1、poll_initwait:初始化轮询等待队列结构体 (poll_wqueues
) 的所有字段,包括函数指针的初始化,后面用于驱动中回调__pollwait
。
2、for循环:遍历每个fd并调用vfs_poll
,vfs_poll
针对传入的fd,调用其各自的poll函数(由设备驱动程序实现,比如sock_poll
)。之后若满足一定条件则跳出循环。
3、poll_freewait:清理等待队列。
后面出一篇文章详细讨论do_select()
I/O多路复用学习(二)do_select分析
__pollwait
__pollwait的作用是在等待队列上注册一个新的节点(),并初始化poll_table_entry
的成员。
1、poll_get_entry:从轮询等待队列结构体 (poll_wqueues
) 中获取一个空闲的poll_table_entry
结构体实例
2、init_waitqueue_func_entry:初始化poll_table_entry
结构体实例,包括函数指针的初始化,后面用于驱动中回调pollwake。
3、add_wait_queue:向等待队列添加一个节点
pollwake
当监视的文件描述符上发生了感兴趣的事件时(如可读,可写等),设备驱动将触发回调函数pollwake。pollwake会将进程或线程从睡眠状态唤醒。
select缺点
1、select默认支持的描述符有限,为1024(可以通过命令ulimit -n 2048临时修改,也可以修改Linux内核头文件posix_types.h修改__FD_SETSIZE的值,但是要重新编译内核);
2、每次调用需要把fd集合在内核态和用户态间拷贝传递两次,在fdset很大时效率低;
3、select内部监视fd是通过轮询的方式,时间复杂度高,效率低;
4、每次调用后需要重新设置fdset,麻烦。