Epoll学习心得

 首先,我们应该知道Epoll可以完成什么任务:

    我们可以把Epoll理解成为这样一个人,我们可以把她大概想象成为一个公司很多老总所共有的一个漂亮的女秘书,老总们都很忙,所有人和老总中的任何一个预约都要经过这位女秘书(我们称之为小M),当然,这件事需要老总的授权。

    现在,张总授权小M,告诉她,如果有人想送钱,你提醒一下,小M记录下,张总等着人送钱。(ET模式下,只提醒一次);

    李总授权小M,告诉他,如果有漂亮姑娘找,你提醒一下,小M记录下,李总等着漂亮姑娘找;

    王总授权小M,告诉她,如果有有关部门的领导来找,你提醒一下,小M记录下,王总等着有关部门领导。

    但不是现在就开始啊,中午了,我们先去吃个饭,什么时候可以开始提醒,我们再告诉你。

下午2点,老总告诉小M可以开始了,然后,他们就去睡觉了,这样他们就可以少消耗点人民所共有的空气,节约国家的能量。


    一旦有被通知需要注意或者监听的事件进入,因为小M只关注了监听的事件类型,所以事件一来,她就直接把她扔进了待处理事件列表,并且大喊一声“来事儿啦!".


    然后张总看第一件事,不是找自己的,扔给了李总,随后查看第二件事,李总一看是找自己的,就直接办了。。。。如此循环下去,直到所有的事情处理完毕。


    这样的处理方式似乎还不够好,因为还是需要每个老总(或者多安排那么一个人)去比对去分发,如果每个老总能在交代任务的时候,再附上一张记录与自己相关事件的纸,这张纸上只记录与该人对应的事情,似乎就提高了老总的工作效率。

    于是这样就又出现了一个问题,来的人只会说想做什么事情,来人不知道这家公司内谁分别负责什么事情,那么就需要小M来对任务进行比对分发,这无疑增加了小M的工作量,Epoll实际上将小M解放了出来,提高了小M的工作效率,而对任务的分发终究还是有人做。

那么这个问题是怎么解决的呢。在注册event的时候,event结构里本身就包含一个指向处理人或者处理的方法函数或者进程或者线程,在遍历events的时候,直接扔到了合适的地方。遍历事件的人/方法,如果抽象出来,就是那个分发任务的人,但这个人是不在Epoll里干活的,在Epoll里干活的只有小M一个。

    看完这些再去理解Epoll的几个函数,就方便多了,而不太需要再去关注什么poll和select机制。


epoll_create     想用Epoll,你得先造个实例出来,这是面向对象的思想,应该不用我说了,按上面的理解,就是你需要先把你的小M创造出来。返回值就是一个描述符,我们可以理解为一个独一无二的代号或者昵称。

epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

                        这个函数(如果第二个参数是EPOLL_CTL_ADD)就是告诉小M要去关注哪里的什么事情,第一个参数epfd,就是前面创建出来的描述符,或者说是你要告诉关注,这里是小M;第二个参数表示要对第三个参数的操作选择;第三个参数是告诉小M要关注的地方,也就是这段话里第一句中所说关注哪里,张总可能告诉她,只关注打电话来送钱的。这个打电话来就是第三个参数了,具体到Linux下的编程上,一般就是一个描述符了。

                        event是一个指向epoll_event结构体类型 的 指针。这个结构体里 保存了事件的类型,以及前面我们提到的 需要处理这件事的人/线程/进程 或者 指向 处理这件事的方法/函数 的指针。


typedef union epoll_data
{
void* ptr;
int fd;
  __uint32_t   u32;
  __uint64_t   u64;
}epoll_data_t;

struct epoll_event
{
  __uint32_t   events;/* Epoll events */
epoll_data_t data;/* User data variable */
};

                        对这个函数理解到这里就算能用了,但在实际项目中可能会有更多的要求,可否对一个监听渠道添加监听事件?直接用 第二个参数 EPOLL_CTL_ADD 再次添加是不行的,只能用EPOLL_CTL_MOD修改,或者用EPOLL_CTL_DEL删掉时间重新添加。而事件类型之间是可以用位或 |  拼到一起的,一般只需要其中两三个拼就够了。


enum EPOLL_EVENTS
  {
    EPOLLIN = 0x001,
#define EPOLLIN EPOLLIN
    EPOLLPRI = 0x002,
#define EPOLLPRI EPOLLPRI
    EPOLLOUT = 0x004,
#define EPOLLOUT EPOLLOUT
    EPOLLRDNORM = 0x040,
#define EPOLLRDNORM EPOLLRDNORM
    EPOLLRDBAND = 0x080,
#define EPOLLRDBAND EPOLLRDBAND
    EPOLLWRNORM = 0x100,
#define EPOLLWRNORM EPOLLWRNORM
    EPOLLWRBAND = 0x200,
#define EPOLLWRBAND EPOLLWRBAND
    EPOLLMSG = 0x400,
#define EPOLLMSG EPOLLMSG
    EPOLLERR = 0x008,
#define EPOLLERR EPOLLERR
    EPOLLHUP = 0x010,
#define EPOLLHUP EPOLLHUP
    EPOLLRDHUP = 0x2000,
#define EPOLLRDHUP EPOLLRDHUP
    EPOLLONESHOT = (1 << 30),
#define EPOLLONESHOT EPOLLONESHOT
    EPOLLET = (1 << 31)
#define EPOLLET EPOLLET
};


                        似乎很遗憾的是,这些事件类型都被集中在了一个event里面,也就是说 处理人/线程/进程/方法/函数 是确定的了。

                        不过也不十分遗憾,因为这一个监控渠道不会真的像打电话那样会有各种稀奇百怪的事情需要处理,具体到编程上一个渠道/描述符基本上也就负责一个相关事务,具体到文件上无非就是可读或者可写,绝对不会出现文件着火了怎么办,文件想吃饭了怎么办。


接下来就是进入处理环节的一个函数了


int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)

                    这个函数一般都放在一个循环里面,这个函数之后就是处理,也就是遍历参数二中的events时间列表。然后返回来再次等待被通知"出事儿啦!“

                    参数1 是之前创建的描述符/代号

                    参数3 是传输events的时间数量

                    参数4 是超时控制


读到这里相信大家对Epoll机制已经非常了解了,起码简单使用起来已经问题不大了,如果希望对参数或者返回值有更好的了解,建议大家还是去man一下,当然,稍后如果我再有时间也会补充上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值