您的位置:首页 > 运维架构 > Linux

unix select() 任务调度机制分析

2016-06-17 09:53 267 查看
  参考资料:【1】Unix环境高级编程(第二版)P381 14.5.1 select和pselec函数;

                    【2】 selec函数详细用法解析  http://blog.chinaunix.net/uid-21411227-id-1826874.html

        最近在学习live555,发现live555 server的任务调度主要是基于select()模型实现,所以决定对select()详细学习的。因为select函数真的很强大。

1、  首先给出select函数的原型:  

          #include <sys/select.h>

            int select(int maxfdp1,fd_set *restrict  readfds,fd_set  *  restrict writefds,fd_set *restrict exceptfds,struct timeval *restrict timeout);

 注:select 函数依从POSIX平台。

2、参数说明:

        restrict,C语言中的一种类型限定符(Type
Qualifiers),用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容。

   
1)、struct timeval {

                                         long  tv_sec;           //单位是秒

                                          long tv_usec;          //单位是毫秒 

                                       }

该参数是指定程序调用该函数时获取返回值愿意等待时间,有三种情况:

timeout == NULL(注意:传入参数为NULL,而不是timeval参数都为0)

永远等待。阻塞直到有信号则中断此无限等待。当所指定描述符中的一个已经准备好或者捕捉到一个信号则返回。如果捕捉到一个信号,返回-1,errno设置为EINTR

timeout->tv_sec ==0 &&  timeout->tv_usec ==0

         完全不等待。测试所有指定的描述符并立即返回。得到多个描述符的状态而不阻塞select函数的轮询方法。

timeout->tv_sec !=0 &&  timeout->tv_usec !=0

         等待指定的时间  tv_sec+tv_usec S,当指定的描述符之一准备好,或者当指定的时间值已经超过时立即返回。

        (注:posix.1 允许在实现中修改timeval结构中的值,所以在select后,你不能指望该结构仍旧保持调用select之前所包含的值。FreeBSD 5.2.1 Mac OS X 10.3和Solaris 9都保持高结构中的值不变,但是Linux 2.4.22,若在该时间尚未超过timeval时间就返回select时,那么将用余留时间值更新该结构)

        2) fd_set*readfds 

     是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。 
       3) fd_set*writefds

    是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。 
        4) fd_set *errorfds

     同上面两个参数的意图,用来监视文件错误异常。 

        5) int maxfdp1:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符集中找出最大描述符编号值,然后加1,这就是第一个参数值,不能错!在Windows中这个参数的值无所谓,可以设置不正确。 

           
2)、3)、4)三个参数是指向描述符的指针。这三个描述符集说明了我们关系的可读、可写或处于异常条件的各个描述符,每个描述符存放在一个fd_set数据类型中。
        例:

 
                                        


6)
 返回值 整型

负值:select错误。当所指定的
dee0
描述符都没准备好时捕捉到一个信号中断select函数,返回-1.此时不修改其中任何描述符集。
正值:表示准备好的描述符数,该值是三个描述符集中已准备好的描述符数之和。三个描述符集中人就打开的位对应于已准备好的描述符。 
0:描述符集没有准备好,等待超时,没有可读写或错误的文件。此时所有描述符集皆被清零。                         3.错误代码
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。

EBADF 文件描述词为无效的或该文件已关闭

EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足
4.举例

从网络上接受数据写入一个文件中。 

main() 



    int sock; 

    FILE *fp; 

    struct fd_set fds; 

    struct timeval timeout={3,0}; //select等待3秒,3秒轮询,要非阻塞就置0 

    char buffer[256]={0}; //256字节的接收缓冲区 

    /* 假定已经建立UDP连接,具体过程不写,简单,当然TCP也同理,主机ip和port都已经给定,要写的文件已经打开 

    sock=socket(...); 

    bind(...); 

    fp=fopen(...); */ 

    while(1) 

   { 

        FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化 

        FD_SET(sock,&fds); //添加描述符 

        FD_SET(fp,&fds); //同上 

        maxfdp=sock>fp?sock+1:fp+1;    //描述符最大值加1 

        switch(select(maxfdp,&fds,&fds,NULL,&timeout))   //select使用 

        { 

            case -1: exit(-1);break; //select错误,退出程序 

            case 0:break; //再次轮询 

            default: 

                  if(FD_ISSET(sock,&fds)) //测试sock是否可读,即是否网络上有数据 

                  { 

                        recvfrom(sock,buffer,256,.....);//接受网络数据 

                        if(FD_ISSET(fp,&fds)) //测试文件是否可写 

                            fwrite(fp,buffer...);//写入文件 

                         buffer清空; 

                   }// end if break; 

          }// end switch 

     }//end while 

}//end main 

     
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux select