先看下列的例子程序
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <assert.h>
#define STDIN 0
#define TRUE 1
#define FALSE 0
#define ulong unsigned long
static struct timeval timeLast;
static volatile char TmoutEnable;
void timeEnable()
{
int res = gettimeofday( &timeLast, NULL );//获取当前时间计数
assert( res == 0 );
TmoutEnable = TRUE;
}
void timerECE( )//毫秒定时器
{
ulong ulDeltaMS;
struct timeval timeCur;//当前时间
if( TmoutEnable )
{
if( gettimeofday( &timeCur, NULL ) != 0 ){
/* 获取当前时间失败,等等下次获取*/
}
else
{
ulDeltaMS = ( timeCur.tv_sec - timeLast.tv_sec ) * 1000L + ( timeCur.tv_usec - timeLast.tv_usec ) /1000L;
printf("the time of input:%ld ms/n",ulDeltaMS);
TmoutEnable = FALSE;
}
}
}
int isready(int fd)
{
int rc,rs;
fd_set fds;
struct timeval tv;
tv.tv_sec=5;
tv.tv_usec=500000;
FD_ZERO(&fds);
FD_SET(fd,&fds);
printf("set timeout's time:%d millisecond /n",tv.tv_sec*1000+tv.tv_usec/1000);
timeEnable();
rc = select(fd+1, &fds, NULL, NULL, &tv);
if (rc < 0)
return -1;
if (FD_ISSET(fd,&fds)) {
rs=1;
printf("yes ,I'Ready/n");
}else{//超时后
rs=0;
timerECE();
printf("there's time out/n");
}
timerECE();
return rs;
}
int main()
{
int rs;
rs=isready(STDIN);
printf("rs:%d/n",rs);
}
select函数用来查询设备是否可读写,或是否处于某种状态。
select()函数说明:
select()函数的接口主要是建立在结构'fd_set'的基础上。'fd_set' 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,所以linux用一组标准的宏定义来处理此类变量:
fd_set set;
FD_ZERO(&set); /* 将set清零 */
FD_SET(fd, &set); /* 将新的文件描述符fd加入set */
FD_CLR(fd, &set); /* 将fd从set中清除 */
FD_ISSET(fd, &set); /* 如果fd在set集中,则返回真 */
不同系统平台,一个fd_set集的最大描述符不同,不过你可以通过sizeof(fd_set) 的返回来判断你的平台上支持多少个文件描述符。在 Linux中,sizeof(fd_set)的结果是128 * 8 = FD_SETSIZE=1024)
select函数原型:
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
注释:
n
需要检查的文件描述符个数,n应该比是三组fd_set---(readfds,writefds,exceptfds)中最大数
更大,而不是实际文件描述符的总数。
readset
用来检查可读性的一组文件描述符。
writeset
用来检查可写性的一组文件描述符。
exceptset
用来检查意外状态的文件描述符。(注:错误并不是意外状态)
timeout
等待最长时间,如果timeout==NULL,则进入无限期等待,如果其中tv_sec和tv_usec都等于0, 则文件描述符
的状态不被影响,但函数并不挂起
返回值是返回响应操作的对应操作文件描述符的总数,且三组数据均在恰当位置被修改,只有响应操作的那一些没有修改。可用FD_ISSET宏来查找此操作符(参考上例子)。
当然如果我们把NULL指针作为fd_set传入的话,这就表示我们对这种操作的发生不感兴趣,但select() 还是会等待直到其发生或者超过等待时间,不过我想这样没什么意义吧。。
例子中还用到的linux时间操作函数,在上一篇日志中已经有详细说明,此就不多介绍了。
参考:
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)唤醒等待队列
2011-02-2420:50:13