前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux编程(阻塞和非阻塞IO)

Linux编程(阻塞和非阻塞IO)

作者头像
用户2617681
发布2019-08-08 15:24:14
5.4K0
发布2019-08-08 15:24:14
举报
文章被收录于专栏:秘籍酷秘籍酷

Linux设备驱动中的阻塞和非阻塞I/0,简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式。

一、基本概念:

  • 阻塞操作:是指在执行设备操作时,若不能获得资源,则挂起进程直到满足操作条件后再进行操作。被挂起的进程进入休眠, 被从调度器移走,直到条件满足。
  • 非阻塞操作:在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以进行操作。非阻塞应用程序通常使用select系统调用查询是否可以对设备进行无阻塞的访问最终会引发设备驱动中 poll 函数执行。

二、两种操作

阻塞地读取一个字符:

char buf; fd = open("/dev/ttyS1",O_RDWR); ..... res = read(fd,&buf,1); //当串口上有输入时才返回,没有输入则进程挂起睡眠 if(res == 1) { printf("%c/n",buf); }

非阻塞地读一个字符:

char buf; fd = open("/dev/ttyS1",O_RDWR|O_NONBLOCK); //O_NONBLOCK 非阻塞标识 ..... while(read(fd,&buf,1)!=1); //串口上没有输入则返回,所以循环读取 printf("%c/n",buf);

阻塞操作常常用等待队列来实现,而非阻塞操作用轮询的方式来实现。非阻塞I/O的操作在应用层通常会用到select()和poll()系统调用查询是否可对设备进行无阻塞访问。select()和poll()系统调用最终会引发设备驱动中的poll()函数被调用。这里对队列就不多介绍了,大家可以看看数据结构里面的知识点。

应用层的select()原型为:

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptionfds, struct timeval *timeout);

numfds 的值为需要检查的号码最高的文件描述符加1,若select()在等待timeout时间后,若没有文件描述符准备好则返回。

应用程序为:

#inlcude------ int main(void) { int fd,num; char rd_ch[BUFFER_LEN]; fd_set rfds,wfds; //读写文件描述符集 //以非阻塞方式打开/dev/globalfifo设备文件 fd=open("/dev/globalfifo",O_RDWR|O_NONBLOCK); if(fd != -1) {

//FIFO 清零 if(ioctl(fd,FIFO_CLEAR,0) < 0) { printf("ioctl cmd failed /n"); } while(1) { FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(fd,&rfds); FD_SET(fd,&wfds); select(fd+1,&rfds,&wfds,null,null); } } }

下面说说设备驱动中的poll()函数,函数原型如下:

static unsigned int poll(struct file *file, struct socket *sock,poll_table *wait) //第一个参数是file结构体指针,第三个参数是轮询表指针,这个函数应该进行两项工作

  • 对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头添加到poll_table
  • 返回表示是否能对设备进行无阻塞读,写访问的掩码

驱动函数中的poll()函数典型模板如下:

static unsigned int xxx_poll(struct file *filp,struct socket *sock,poll_table *wait) { unsigned int mask = 0; struct xxx_dev *dev = filp-&gt;private_data; //获得设备结构体指针 ... poll_wait(filp,&amp;dev-&gt;r_wait,wait); //加读等待队列头到poll_table poll_wait(filp,&amp;dev-&gt;w_wait,wait); //加写等待队列头到poll_table ... if(...) //可读 mask |= POLLIN | POLLRDNORM; if(...) //可写 mask |= POLLOUT | POLLRDNORM; ... return mask; }

三、总结

阻塞与非阻塞操作:

  • 定义并初始化等待对列头;
  • 定义并初始化等待队列;
  • 把等待队列添加到等待队列头
  • 设置进程状态(TASK_INTERRUPTIBLE(可以被信号打断)和TASK_UNINTERRUPTIBLE(不能被信号打断))
  • 调用其它进程
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 秘籍酷 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档