今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对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------ main() { 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); } } } |