epoll 使用详解--epoll_wait

关键API:

epoll_wait, epoll_pwait, epoll_pwait2 等待epoll中的I/O事件发生。

概要:

1
2
3
4
5
#include <sys/epoll.h>
 
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask);
int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask);

参数描述:

  epfd :epoll文件描述符
  events :接口的返回参数,一般都是一个数组,数组长度大于等于maxevents。
  maxevents:期望捕获的事件的个数。
  timeout :超时时间(>=0),单位是毫秒ms,-1表示阻塞,0表示不阻塞。

  sigmask:需要屏蔽信号的掩码,可以避免wait时被信号打断。

 

函数返回值:

  ret: 函数返回值
    正常捕获事件后返回事件的个数。
    超时返回0.

  只有在下面的情况下才会返回:
    1、有至少一个事件发生。
    2、调用过程中被信号中断?
    3、超时。

  events:函数输出参数
    这个和create时是同一个数据结构,events就是很多事件的集合,data就是create时设置的值(原样返回)。

1
2
3
4
struct epoll_event {
    uint32_t events; /* Epoll events */
    epoll_data_t data; /* User data variable */
  };

拓展API:

  epoll_pwait()
    epoll_wait()与epoll_pwait()的区别类似,select(2)与pselect(2)。epoll_pwait()可以让程序安全的等到事件的发生,一般的epoll_wait()处理线程,在阻塞期间是可能被信号中断的。
    当线程处理完信号函数以后,再次返回时,epoll_wait()不会继续阻塞,而是推出,返回-1。
  调用方法:
    ready = epoll_pwait(epfd, &events, maxevents, timeout, &sigmask);
  实现:
    函数的内部可以理解为原子的调用了下面的这些函数:

1
2
3
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, &events, maxevents, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);

  参数:
    sigmask: 希望阻塞的信号列表,如果为NULL,这个api和epoll_wait()功能一模一样。

  epoll_pwait2()
    和epoll_pwait()区别就是增加了超时时间。
  调用:

1
int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask);

  参数:
    timeout:可以指定纳秒级别的时间。

返回值:   

成功返回I/O事件的个数,超时返回0。失败返回-1,会设置错误码error。

错误码:   

  EBADF :apfd不是一个有效的描述符
  EFAULT :参数events指向的内存区域不可写。
  EINTR :阻塞过程中被信号中断,epoll_pwait()可以避免,或者错误处理中,解析error后重新调用epoll_wait()。

  EINVAL :epfd不是一个epoll文件描述符,或者参数maxevents小于等于0。

注释:   

  1、当某个线程阻塞在epoll_wait(),另外一个线程可以往这个epfd中添加新的套接字。而且如果这个套接字事件发生,也会被阻塞的线程捕获事件。
  2、如果epoll中已经有超过maxevents 个事件,当前成功返回后,再次调用,获取的事件将从上次取得结尾地方开始获取。可以理解为内部是一个队列,先进先出,事件再次
  触发只能往后面插入,epoll_wait()从头取,避免出现饿死的情况。
  3、如果epoll_wait()一个空的epfd,将会导致永远阻塞。如果epoll_wait()过程中,epfd监视列表被其它线程清空了也一样。


posted @   核心已转储  阅读(10415)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示