IO 的阻塞和非阻塞二:轮询操作

IO 的阻塞用的是 等待队列
非阻塞用的是 轮询

 

1. 简介:

轮询操作主要是实现的是用户层 select 和 poll 的支持,用户层的 select()/poll() 会调用设备驱动中的 poll() 函数被执行 ,对 poll 函数的扩展是 epoll()

select() 和 poll() 系统调用的本质一样,前者是 BSD UNIX 中引入,后者在 System V 中引入。

 

2. 应用程序中:

应用程序中使用最广泛的是 select() 系统调用。

int select(int numfds,

        fd_set *readfds, fd_set *writefds, fd_set *exceptfds,

        struct timeval *timeout);

readfds、writefds、exceptfds 分别是被 select()监视的读、写和异常处理的文件描述符集

numfds,文件描述符集中的文件的个数,因为对于用户来说,文件描述符是从3(0,1,2应经占用了)开始,并且系统会自动的加一的打开其他的文件描述符,所以此值是需要检查的号码最高的文件描述符加 1。

timeout,一个指向 struct timeval类型的指针,它可以使select()在等待timeout时间后若没有文件描述符准备好则返回。如果是NULL,则一直阻塞的等待。

struct timeval {
    int tv_sec; /* 秒 */
    int tv_usec; /* 微秒 */
}; 

 

对文件描述符集合的操作方法如下图:

 

3. 设备驱动中:

设备驱动中用 file_operations 机构体中的 .poll 来承接用户层的传输

 

unsigned int(*poll)(struct file * filp, struct poll_table* wait);

filp,file 结构体指针

wait,轮询表指针,位于内核中,用户只需要使用就行

 

poll_wait 可以向驱动的 poll_table 结构添加一个等待队列,这个函数不会引起阻塞

void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);

filp,file 结构体指针

queue,要添加的等待队列的指针

wait,poll_table 的结构体的指针,同上边的 poll 指针的 wait 参数,这里只要使用就好

它的返回值:

POLLIN,0x0001 设备可以无阻塞的读

POLLOUT,0x0004 设备可以无阻塞的写

POLLPRI

POLLERR

POLLNVAL

 

设备驱动中使用poll的典型的模板如下:

static unsigned int xxx_poll(struct file *filp, poll_table *wait)
{ 
    unsigned int mask = 0;
    struct xxx_dev *dev = filp->private_data; /*获得设备结构体指针*/
    ... 
    poll_wait(filp, &dev->r_wait, wait);/* 加读等待队列头 */
    poll_wait(filp, &dev->w_wait, wait);/* 加写等待队列头,由 wake_up()一系列的函数唤醒 */
    if (...) /* 可读 */
    mask |= POLLIN | POLLRDNORM; /*标示数据可获得*/
    if (...) /* 可写 */
    mask |= POLLOUT | POLLWRNORM; /*标示数据可写入*/
    ... 
    return mask;
} 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值