现在的位置: 首页 > 综合 > 正文

linux下select函数的使用

2018年02月09日 ⁄ 综合 ⁄ 共 2760字 ⁄ 字号 评论关闭
先看下列的例子程序
#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

抱歉!评论已关闭.