前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

epoll

作者头像
linjinhe
修改2018-06-06 22:46:55
1.7K0
修改2018-06-06 22:46:55
举报
文章被收录于专栏:linjinhe的专栏

大学还没毕业的时候,为了应付毕业找工作,了解过所谓“事件驱动”的一些情况(其实就是select/poll/epoll),特别是epoll。不过现在搬砖搬久了,也就渐渐忘记……忽然心血来潮,复习一下。温故而知新——希望有新的认识。

开始

epoll是Linux提供的I/O event notification facility。在需要监听的fd数量很多(成千上万)而同一时刻可读/可写的数量又比较少(几个?几十个?几百个?)的情况下,性能要明显优于select、poll。

API

与epoll直接相关的API有: 创建epoll fd:epoll_create/epoll_create1 操作epoll fd:epoll_ctl 监听epoll fd:epoll_wait/epoll_pwait

创建

代码语言:javascript
复制
int epoll_create(int size);
int epoll_create1(int flags);
  • epoll_create用于创建一个epoll fd。从Linux2.6.8开始,size参数就被废弃了,但是使用时传入的参数必须大于0。
  • epoll_create1的参数flags可以为0或EPOLL_CLOEXEC。
    • flags为0:epoll_create1的作用和epoll_create一样。
    • flags为EPOLL_CLOEXEC:将返回的epoll fd设置为close on exec

操作

代码语言:javascript
复制
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
  • 在epfd上设置(op)描述符fd的事件(event)。
  • epfd是epoll_create的返回值。
  • fd是想要操作的文件描述符。
  • op是操作的类型,其取值有:
    • EPOLL_CTL_ADD
    • EPOLL_CTL_MOD
    • EPOLL_CTL_DEL
  • event是fd所关心的事件。对于EPOLL_CTL_DEL,可以传NULL(BUG:Linux2.6.9之前不能传NULL)。
代码语言:javascript
复制
typedef union epoll_data {
    void* ptr;
    int fd;
    uint32_t u32;
    uint64_t u64;
} epoll_data_t;
struct epoll_event {
    uint32_t events;     // events is a bit set
    epoll_data_t data;
};
  • epoll_event的成员events是一个bit set。其值可以是下面各值的或。
    • EPOLLINT:监听可读事件。
    • EPOLLOUT:监听可写事件。
    • EPOLLRDHUP :监听对端断开连接。
    • EPOLLPRI:外带数据。
    • EPOLLERR:Error condition happened on the associated file descriptor.
    • EPOLLHUP:Hang up happened on the associated file descriptor.
    • EPOLLET:边沿触发,epoll监听的fd默认是电平触发。
    • EPOLLONESHOT:对应fd的事件被触发通知后,需要重新调用epoll_ctl对其进行修改(EPOLL_CTL_MOD),才能恢复事件触发通知。

监听

代码语言:javascript
复制
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);

监听的接口比较简单,暂时没什么好介绍。

线程安全

While one thread is blocked in a call to epoll_pwait(), it is possible for another thread to add a file descriptor to the waited-upon epoll instance. If the new file descriptor becomes ready, it will cause the epoll_wait() call to unblock.

假设我们有一个多线程的程序,一个线程负责建立连接和管理其它线程,我们暂且称之为master线程;多个线程负责处理连接后的业务逻辑,我们称之为worker线程。master线程建立连接后,调用epoll_ctl将socketfd注册到某个worker线程。worker线程调用epoll_wait监听事件。这样是不是线程安全的呢?

上面那段英文,有一个单词特别重要——waited-upon。当worker线程被阻塞在epoll_wait的时候,另一个线程调用epoll_ctl往其epfd注册fd,是线程安全的。但是这里有一个临界条件:worker线程可能刚好被唤醒,而不是阻塞在epoll_wait,此时这样的操作就不是线程安全的。

If a file descriptor being monitored by select() is closed in another thread, the result is unspecified. On some UNIX systems, select() unblocks and returns, with an indication that the file descriptor is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned and the I/O operations was performed). ** On Linux (and some other systems), closing the file descriptor in another thread has no effect on select(). In summary, any application that relies on a particular behavior in this scenario must be considered buggy. **

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016.10.29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开始
  • API
    • 创建
      • 操作
      • 监听
      • 线程安全
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档