linux下select函数的使用

    技术2022-05-20  72

    先看下列的例子程序 #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

    最新回复(0)