学习手册:Linux操作系统下的poll和select


计算机的发展,Linux操作系统越来越成为主流,你了解Linux操作系统系统么?你是Linux操作系统系统的应用者么?本文为你详细介绍Linux操作系统下的poll和select ,为你在学习Linux操作系统下的poll和select 时起一定的作用。    

select()函数的作用
系统调用select和poll的后端实现,用这两个系统调用来查询设备是否可读写,或是否处于某种状态。如果poll为空,则驱动设备会被认为即可读又可写,返回值是一个状态掩码
如何使用select()函数?
select()函数的接口主要是建立在一种叫'fd_set'类型的基础上。它('fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:

  1. fd_set set;  
  2. FD_ZERO(&set);   /* 将set清零 */  
  3. FD_SET(fd, &set);/* 将fd加入set */  
  4. FD_CLR(fd, &set);/* 将fd从set中清除 */  
  5. FD_ISSET(fd, &set);   /* 如果fd在set中则真 */ 

在过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查 fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系统相关的*,同时检查你的系统中的select() 的man手册。有一些系统对多于1024个文件描述符的支持有问题。[译者注: Linux操作系统就是这样的系统!你会发现sizeof(fd_set)的结果是128(*8 = FD_SETSIZE=1024) 尽管很少你会遇到这种情况。]

select的基本接口十分简单:

  1. int select(int nfds, fd_set *readset, fd_set *writeset,  
  2. fd_set *exceptset, struct timeval *timeout); 

其中:

nfds
需要检查的文件描述符个数,数值应该比是三组fd_set中最大数
更大,而不是实际文件描述符的总数。
readset   
用来检查可读性的一组文件描述符。
writeset
用来检查可写性的一组文件描述符。
exceptset
用来检查意外状态的文件描述符。(注:错误并不是意外状态)
timeout
NULL指针代表无限等待,否则是指向timeval结构的指针,代表最
长等待时间。(如果其中tv_sec和tv_usec都等于0, 则文件描述符
的状态不被影响,但函数并不挂起)

函数将返回响应操作的对应操作文件描述符的总数,且三组数据均在恰当位置被修改,只有响应操作的那一些没有修改。接着应该用FD_ISSET宏来查找返回的文件描述符组。

这里是一个简单的测试单个文件描述符可读性的例子:

  1.  int isready(int fd)  
  2.  {  
  3. int rc;  
  4. fd_set fds;  
  5. struct timeval tv;  
  6.       
  7. FD_ZERO(&fds);  
  8. FD_SET(fd,&fds);  
  9.     // tvtv.tv_sec = tv.tv_usec = 0;  
  10.       
  11. //rc = select(fd+1, &fds, NULL, NULL, &tv);  
  12.    rc = select(fd+1, &fds, NULL, NULL, NULL);  
  13. if (rc < 0)  
  14.   return -1;  
  15.       
  16. return FD_ISSET(fd,&fds) ? 1 : 0;  
  17.  }  

当然如果我们把NULL指针作为fd_set传入的话,这就表示我们对这种操作的发生不感兴趣,但select() 还是会等待直到其发生或者超过等待时间。

[译者注:在Linux操作系统中,timeout指的是程序在非sleep状态中度过的时间,而不是实际上过去的时间,这就会引起和非Linux操作系统平台移植上的时间不等问题。移植问题还包括在System V风格中select()在函数退出前会把timeout设为未定义的 NULL状态,而在BSD中则不是这样, Linux操作系统在这点上遵从System V,因此在重复利用timeout指针问题上也应该注意。]

Linux操作系统下select调用的过程:
1.用户层应用程序调用select(),底层调用poll())
2.核心层调用sys_select() ------> do_select()
最终调用文件描述符fd对应的struct file类型变量的struct file_operations *f_op的poll函数。
poll指向的函数返回当前可否读写的信息。
1)如果当前可读写,返回读写信息。
2)如果当前不可读写,则阻塞进程,并等待驱动程序唤醒,重新调用poll函数,或超时返回。
3.驱动需要实现poll函数。
当驱动发现有数据可以读写时,通知核心层,核心层重新调用poll指向的函数查询信息。
poll_wait(filp,&wait_q,wait)    // 此处将当前进程加入到等待队列中,但并不阻塞
在中断中使用wake_up_interruptible(&wait_q)唤醒等待队列

希望本文对你学习Linux操作系统下的poll和select有所帮助。

  1. 详解Linux操作系统中使用Windows分区
  2. 完成Linux汉化轻松应用Linux
  3. Linux技术受风河与NEC垂青
  4. 多样性的Linux桌面
  5. Red Hat宣布企业Linux 6将不再支持安腾

相关内容