eventfd
计数不为零是有可读事件发生,read 之后计数会清零,write 则会递增计数器。如下:
uint64_t u1,u2,u3;
// 写 eventfd,内部 buffer 必须是 8 字节大小;
// 写 3 次
write(efd, &u1 , sizeof(uint64_t)) /* u = 1 */
write(efd, &u2 , sizeof(uint64_t)) /* u = 2 */
write(efd, &u2 , sizeof(uint64_t)) /* u = 3 */
// 读 eventfd
n = read(efd, &u, sizeof(uint64_t));
读到的值是 6(因为 1+2+3)
使用eventfd实现一个消费者和多个生产者:
生产者:是多个线程,会把请求投递到一个 list 中,然后唤醒生产者。
producer:
// 投递请求到链表
list_add( global_list, request )
// 唤醒消费者处理
write(eventfd, &cnt /* 1 */ , 8)
消费者:是一个线程,后台 loop 处理。使用 epoll 监听 eventfd 的可读事件,这样能做到一旦有请求入队,消费者就立马唤醒处理。
consumer
// 添加 eventfd 到监听池
epoll_ctl(ep, EPOLL_CTL_ADD, eventfd, &ee);
loop:
// 等待唤醒
epoll_wait(ep, ... );
// 读取新添加到列表里的元素个数,并且进行处理;
n = read(eventfd, ... )
// 遍历链表处理
for each global_list:
// do something
eventfd是一种特殊的文件描述符,eventfd打开、读写和关闭都效非常高,因为它本质并不是文件,而是kernel在内核空间(内存中)维护的一个64位计数器而已。