• 轮询


    1 int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

      使用非阻塞 I/O 的应用程序通常会使用 select() 和 poll() 系统调用查询是否可对设备进行无阻塞的访问。这两个系统调用最终会引发设备驱动中的 poll() 函数被执行。

    • numfds:此值是需要检查的号码最高的文件描述符加 1 
    • readfds:被 select 监视的读文件描述符集合
    • writefds:被 select 监视的写文件描述符集合
    • exceptfds:被 select 监视的异常处理的文件描述符集合
    • timeout:指向 struct timeval 类型的指针,可使 select 在等待 timeout 时间后若没有文件描述符准本好则返回
    1 struct timeval {
    2     int tv_sec; /**/
    3     int tv_usec; /* 微秒 */    
    4 };

      下列操作来设置、清除、判断文件描述符集合

    1 FD_ZERO(fd_set *set);    /* 清除一个文件描述符集合 */
    2 FD_SET(int fd, fd_set *set);    /* 将一个文件描述符加入文件描述符集合中 */
    3 FD_CLR(int fd, fd_set *set);    /* 将一个文件描述符从文件描述符集合中清除 */
    4 FD_ISSET(int fd, fd_set *set);    /* 判断文件描述符是否被置位 */
     1 #include ...
     2 
     3 #define        FIFO_CLEAR  0x01
     4 #define        BUFFER_LEN    20
     5 
     6 main()
     7 {
     8     int fd, num;
     9     char rd_ch(BUFFER_LEN);
    10     fd_set rfds,wfds;    /* 读/写文件描述符集 */
    11     
    12     /* 以非阻塞方式打开 /dev/xxx  设备文件 */
    13     fd = open("/dev/xxx", O_RDONLY | O_NONBLOCK);
    14     if(fd != -1)
    15     {
    16         /* FIFO 清0 */
    17         if(ioctl(fd, FIFO_CLEAR, 0) < 0)
    18         {
    19             prinf("ioctl command failed
    ");
    20         }
    21         
    22         while(1)
    23         {
    24             FD_ZERO(&rfds);
    25             FD_ZERO(&wfds);
    26             FD_SET(fd, &rfds);
    27             FD_SET(fd, &wfds);
    28             
    29             select(fd + 1, &rfds, &wfds, NULL, NULL);
    30             /* 数据可获得 */
    31             if(FD_ISSET(fd, &rfds))
    32                 prinf("Poll monitor: can be read
    ");
    33             
    34             /* 数据可写入 */
    35             if(FD_ISSET(fd, &wfds))
    36                 prinf("Poll monitor: can be write
    ");
    37         }
    38     }
    39     else
    40     {
    41         prinf("Device open failure
    ");
    42     }
    43 }

     1.1 多路复用 select()

      

      第一次对 n 个文件进行 select 的时候,若任何一个文件满足要求,select 就直接返回;第二次再进行 select 的时候,没有文件满足读写要求,select 进程阻塞且睡眠。

      由于调用 select 的时候,每个驱动的  poll() 接口都会被调用到,实际上执行 select 的进程被挂到了每个驱动的等待队列上,可以被任何一个驱动唤醒,如果 FDn 变得可读写,select 返回

      当多路复用的文件数量庞大,IO流量频繁的时候,一般不太适用使用 select 和 poll ,此情况下,这两个函数表现的性能较差,应使用  epoll。

      epoll  的最大好处是不会随着 fd 的数目增长而降低效率。

    1 /* poll 函数原型 */
    2 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    1 /* 创建一个 epoll 句柄,size 告诉内核要监听多少个 fd */
    2 /* 注:当创建 epoll 句柄后,它本身也会占用一个 fd,所以在使用完 epoll 后,必须调用 close() 关闭 */
    3 int epoll_creat(int size);
    1 /* 告诉内核要监听什么类型的事件 
    2  * 第一个参数是 epoll_creat 的返回值
    3  * 第二个参数表示动作,第三个参数是需要监听的 fd,第四个参数是告诉内核需要监听的事件类型
    4  */
    5 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

      第二个参数的动作包含:

      

      struct epoll_event 结构体为:

      

    • event 可以是以下几个宏的或:
      • EPOLLIN:表示对应的文件描述符可读
      • EPOLLOUT:表示对应的文件描述符可写
      • EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里表示的是有 socket 带外数据到来)
      • EPOLLERR:表示对应的文件描述符发生错误
      • EPOLLHUP:表示对应的文件描述符被挂断
      • EPOLLET:将 epoll 设为边缘触发模式,  
      • EPOLLONESHOT:意味着一次性监听,当监听完这次事件之后,如果还需要继续监听这个 fd 的话,需要再次把这个 fd 加入到 epoll 队列中

      

    1 /* 等待事件的产生,用来从内核得到事件的集合,maxevents 告诉内核本次最多收多少事件,maxevent<= 创建 epoll_creat() 时的size 
    2  * timeout 为超时时间(以毫秒为单位,0意味着立即返回,-1意味着永久等待)
    3  * 返回值是需要处理的事件数目,若返回0,表示已超时
    4  */
    5 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

      

  • 相关阅读:
    超能英雄第一至四季/全集Heroes迅雷下载
    吸血鬼猎人巴菲第一至八季/全集Buffy迅雷下载
    明星伙伴第一至八季/全集Entourage迅雷下载
    实习医生风云第一至九季/全集Scrubs迅雷下载
    阿里云linux图形界面(centos6)
    linux下mysql的root密码忘记解决方
    wdcp支持两种安装方式
    如何搭建lamp(CentOS7+Apache+MySQL+PHP)环境
    丑女贝蒂第一至四季/全集Ugly Betty迅雷下载
    云服务器 ECS Linux 系统安装图形化桌面 (centos7 ubuntu14)
  • 原文地址:https://www.cnblogs.com/kele-dad/p/8747628.html
Copyright © 2020-2023  润新知