zoukankan      html  css  js  c++  java
  • epoll使用总结

    前言

      最近学习了epoll,虽然封装好的epoll只有简单的几个api,但是还是有很多需要注意的细节。

    简介

      编程中往往需要一些IO操作,IO操作最耗时的其实是线程等待IO处理的时间。你如果不知道对面什么时候要写/读,你就只能阻塞在那里等待,无法执行后续事件。或者是说,你同时有很多IO操作,很多IO操作都是在等待的过程,这样的等待,实在是很浪费CPU。这个时候我们可以设计一个对象,让他帮我们管理这些需要进行IO操作的句柄,让他去帮其他线程等待,等到IO操作就绪,再提醒相应线程去处理。这个技术叫做IO多路复用技术,前面提到的帮我们管理的对象,现在被实现出来的有select,poll,epoll。

      那么,这些帮我们管理的对象又是如何实现的呢?假设你现在有10个句柄,然后句柄A进入就绪态,那我怎么就知道句柄A进入就绪态了呢?最粗暴的方法就是,我每一个句柄都检查一遍,然后看下有没有已经就绪的句柄。这是是select、poll中的实现方式,这样的效率可想而知不会太高,如果句柄很多,那你大部分时间都会花费在查找上。

      epoll提出了一个思想,利用函数回调的思想,我不需要去找哪个句柄进入就绪态了,让进入就绪态的句柄自动来找我。底层实现涉及到中断机制,这里暂时不细讲。简单点理解epoll就是,有一个红黑树负责管理句柄和事件,然后当句柄就绪,这个事件会被拷贝一份放到一个双链表中,这个双链表放着所有就绪事件。如果我想取就绪事件,可以去链表中取。

    epoll结构类型和方法

    typedef union epoll_data 
    {
    void *ptr;
    int fd;
    uint32_t u32;
    uint64_t u64;
    } epoll_data_t; /* 提供多种数据类型,如果需要自己定义事件,可以使用ptr指针,不需要的话直接使用fd */
    
    struct epoll_event 
    {
    uint32_t events;    /* 定义epoll发生事件类型,比如EPOLLIN,当发生读事件时,下面的data会被放入双链表中。ET和LT模式也是在此设置 */
    epoll_data_t data;    /* 用户自己定义的事件类型,事件发生时被送到双链表上 */
    };
    
    /* 
     * @brief 创建一个epoll
     * @param __size 最大处理事件数量
     * @return 创建成功返回__epfd
     */
    int epoll_create (int __size); 
    
    /* 
     * @brief 在epoll上添加/删除/修改事件
     * @param __epfd epoll标识
     * @param __op epoll发生事件类型,比如EPOLLIN,EPOLLOUT,EPOLLET
     * @param __fd 需要监听的句柄
     * @param __event 用户自定义数据,用于发生事件后的处理
     * @return 正常返回0,异常返回-1
     */
       
    int epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event); 
    
    /*
     * @brief 用于获取就绪事件
     * @param __epfd epoll标识
     * @param __events 用于接收就绪事件的数组
     * @param __maxevents 设置最大接收数量,一般是__events数组大小
     * @param __timeout 设置超时事件,设置为0是非阻塞,设置为-1为永久阻塞
     * @return 返回就绪事件数量
     */
    
    int epoll_wait (int __epfd, struct epoll_event *__events, int __maxevents, int __timeout);

    epoll常见问题

    1、epoll如何封装?

      一开始我把epoll当作一个事件提醒器,也就是每次有读/写事件时,我接收到提醒,然后执行对应方法。所以起初我在epoll_data中是直接存入句柄,事实上网上很多博客都是这个版本。可是在实践中发现,这种方法很不方便,如果可以把做什么(回调函数)和句柄绑定起来就好了。可以发现epoll_data有个ptr指针成员,那我可以自己封装个结构体,里面存入回调函数,这样事件发生后,我直接执行对应的回调函数不就好了吗?同时结构体可以存入其他变量,用于函数调用。后来发现可以再抽象一波,可以把epoll封装成一个线程,run方法中去等待epoll,获取事件,调用回调函数。这样我只需要考虑外部怎么实现回调函数,然后注册上去就好了。

    2、epoll如何支持多个回调函数?

    3、如果同时有两个事件,会不会冲突?

  • 相关阅读:
    MYSQL定时任务 触发器
    mybatis 学习
    SSM 记录
    环境变量配置
    servlet 拦截器 (filter)
    验证码
    jquery $.ajax({});参数详解
    maven打包忽略静态资源解决办法,dispatchServlet拦截静态资源请求的解决办法
    switch..case..
    HDU 1005 题解
  • 原文地址:https://www.cnblogs.com/scaugsh/p/9454708.html
Copyright © 2011-2022 走看看