一、简介
-
poll机制的底层实现原理就是基于等待队列来实现的。
-
poll()函数,用户空间可以调用之
file_operations->poll,最终会调用操作接口的这个指针
二、应用层 poll()函数相关
1、异步阻塞型IO
-
同步阻塞
应用层调用一个(read/write)对一个文件进行读写操作时,read/write 可能使当前的进程或者线程进入一个休眠态,就是进程/线程阻塞在一个文件的读写操作上(read\write),陷入休眠态的进程/线程只能通过对应的文件设备驱动唤醒自己 -
异步阻塞
在应用层调用poll函数时发生, poll会对多个文件进行轮询操作,去查看每一个文件是否有特定的事件。
若所有文件上都未发生特定的事件,那么poll函数会阻塞当前的进程或者线程。
poll文件涉及多个文件的轮询,所以poll函数引起的进程或者线程休眠,可以被多个设备驱动唤醒。多个文件就对应多个设备驱动。
阻塞在多个文件的轮询操作上(poll),可被多个设备驱动唤醒 -
文件I/O事件类型(常见)
可读、可写、异常…
(poll函数的目的就是查询每个文件的io事件,没查到就会引起休眠)
这些事件是由设备驱动产生的,产生后会唤醒由poll函数导致的进程或者线程休眠,poll函数也能把发生的事件返回给用户空间。
2、poll函数
#include <poll.h>
功能:监视多个文件描述符的指定事件(注意是指定事件,不是所有事件),事件发生时(驱动唤醒poll函数导致休眠的进程线程),把发生的具体事件通知给用户程序
// 参数1:fds数组类型详见下
// 参数2:nfds:pollfd数组的元素个数,要监控的文件描述符数量
// 参数3:timeout:超时时间(ms),不希望进程线程一直休眠在poll函数里
int poll(struct pollfd *fds,nfds_t nfds,int timeout)
struct pollfd
{
// 要监视的文件描述符
int fd;
// 指定要监视的请求事件类型,通过设置一系列的宏来描述
short events; /* 请求的事件类型 */
// revents是返回事件,内核设置具体的返回事件,记录实际发生的事件
short revents; /* 返回的事件类型 */
};
-
events 是要监视的事件
POLLIN:系统内核通知应用层指定数据已经备好,读数据不会被阻塞
POLLPRI :有紧急的数据需要读取
POLLOUT :系统内核通知应用层IO缓冲区已准备好,写数据不会被阻塞
POLLERR :指定的文件描述符发生错误,必须先解决错误,才能对文件作其他的处理。
POLLNVAL:无效的请求
… -
返回值:
成功:发生事件的文件数量,超时返回0
失败:-1
三、测试程序
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <poll.h>
int main(int argc, char *argv[])
{
int ret;
// yiweizhe suoyouchengyuan
struct pollfd fds = {0};
fds.fd = 0;
fds.events = POLLIN;
ret = poll(&fds, 1, 5000);
printf("%s(%d):ret=%d\n", __FILE__, __LINE__, ret);
if(ret == -1)
{
printf("%s(%d):poll error\n", __FILE__, __LINE__);
}
else if(ret)
{
printf("%s(%d):%d files ready\n", __FILE__, __LINE__, ret);
}
else
{
printf("%s(%d):timeout\n", __FILE__, __LINE__);
}
return 0;
}
四、测试现象
/lib/modules/4.1.15 # ./app &
/lib/modules/4.1.15 # app.c(16):ret=0
app.c(27):timeout
[1]+ Done ./app
/lib/modules/4.1.15 #
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # ./app &
/lib/modules/4.1.15 # cat
1
app.c(16):ret=1
app.c(23):1 files ready
1
应该是可以通过单独的cat来向标准输入传递数据。