eventfd是linux 2.6.22后系统提供的一个轻量级的进程间通信的系统调用,eventfd通过一个进程间共享的64位计数器完成进程间通信,这个计数器由在linux内核空间维护,用户可以通过调用write方法向内核空间写入一个64位的值,也可以调用read方法读取这个值。

新建

创建一个eventfd对象,或者说打开一个eventfd的文件,类似普通文件的open操作。

该对象是一个内核维护的无符号的64位整型计数器。初始化为initval的值。

#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);

flags可以以下三个标志位的OR结果:

  • EFD_CLOEXEC : fork子进程时不继承,对于多线程的程序设上这个值不会有错的。
  • EFD_NONBLOCK: 文件会被设置成O_NONBLOCK,读操作不阻塞。若不设置,一直阻塞直到计数器中的值大于0。
  • EFD_SEMAPHORE : 支持 semophore 语义的read,每次读操作,计数器的值自减1。

读操作

读取计数器中的值。

typedef uint64_t eventfd_t;
int eventfd_read(int fd, eventfd_t *value);
  1. 如果计数器中的值大于0:
  • 设置了 EFD_SEMAPHORE 标志位,则返回1,且计数器中的值也减去1。
  • 没有设置 EFD_SEMAPHORE 标志位,则返回计数器中的值,且计数器置0。
  1. 如果计数器中的值为0:
  • 设置了 EFD_NONBLOCK 标志位就直接返回-1。
  • 没有设置 EFD_NONBLOCK 标志位就会一直阻塞直到计数器中的值大于0。

写操作

向计数器中写入值。

int eventfd_write(int fd, eventfd_t value);
  1. 如果写入值的和小于0xFFFFFFFFFFFFFFFE,则写入成功

  2. 如果写入值的和大于0xFFFFFFFFFFFFFFFE

  • 设置了 EFD_NONBLOCK 标志位就直接返回-1。
  • 如果没有设置 EFD_NONBLOCK 标志位,则会一直阻塞直到read操作执行

关闭

#include <unistd.h>
int close(int fd);

示例

示例1-一读一写

#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream> int main() {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
eventfd_write(efd, 2);
eventfd_t count;
eventfd_read(efd, &count);
std::cout << count << std::endl;
close(efd);
}

上述程序主要做了如下事情:

  • 创建事件,初始计数器为0;
  • 写入计数2;
  • 读出计数2
  • 关闭事件

示例2-多读多写

#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream> int main() {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
eventfd_write(efd, 2); // 写入2,计数器为2
eventfd_write(efd, 3); // 写入3, 计数器为2 + 3 = 5
eventfd_write(efd, 4); // 写入3, 计数器为5 + 4 = 9
eventfd_t count;
int read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl; // 0
std::cout << "count=" << count << std::endl; // count = 9
read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl; // -1,返回失败
std::cout << "count=" << count << std::endl; // count = 9,为原来的值
close(efd);
}

示例3-EFD_SEMAPHORE标志位的作用:

#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream> int main() {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE);
eventfd_write(efd, 2); // 写入2,计数器为2
eventfd_t count;
int read_result = eventfd_read(efd, &count); // count = 1,计数器自减1,为1
std::cout << "read_result=" << read_result << std::endl; // 0
std::cout << "count=" << count << std::endl; // 1
read_result = eventfd_read(efd, &count); // count = 1,计数器自减1,为0
std::cout << "read_result=" << read_result << std::endl; // 0
std::cout << "count=" << count << std::endl; // 1
read_result = eventfd_read(efd, &count); // 读取失败
std::cout << "read_result=" << read_result << std::endl; // -1,读取失败
std::cout << "count=" << count << std::endl; // 1
close(efd);
}

可以看到设置了EFD_SEMAPHORE后,每次读取到的值都是1,且read后计数器也递减1。

参考

微信公共号

NFVschool,关注最前沿的网络技术。

原文阅读

最新文章

  1. Java_类似java.lang.VerifyError: Expecting a stackmap frame at branch target 22 in method的解决方法
  2. STM32F之IAR6.5 J-Link程序下载错误
  3. struts2 Advanced Learning
  4. 07 Linux su和sudo命令的区别
  5. C语课设心得分享(三)
  6. C字符串和C++中string的区别 &amp;amp;&amp;amp;&amp;amp;&amp;amp;C++中int型与string型互相转换
  7. SQL按日期Datatime来比较大小
  8. JS获取日期和时间
  9. 使用ffmpeg 对视频截图,和视频转换格式
  10. C#属性和字段
  11. hadoop的安装和配置(三)完全分布式模式
  12. 【mysql】 操作 收集持续更新
  13. Ubuntu16.04安装Redis
  14. rn下的弹性布局
  15. Visual自动添加CSS兼容前缀
  16. [转]How can I install the VS2017 version of msbuild on a build server without installing the IDE?
  17. Python的web服务器
  18. Ladies&#39; Choice UVALive - 3989 稳定婚姻问题 gale_shapley算法
  19. Windows 10 上安装 3D Studio Max 2016 报错的解决办法
  20. 编写高质量代码--改善python程序的建议(七)

热门文章

  1. linux上hosts文件如何配置
  2. LibreOJ β Round #2」贪心只能过样例
  3. 吴裕雄--天生自然 R语言开发学习:分类(续一)
  4. ARTS 第 1 周
  5. 手机预装APP“死灰复燃”,这颗“毒瘤”到底怎么了
  6. PHP实现 3des加密解密
  7. vue.js 中使用(...)运算符报错
  8. 原生js实现replace方法
  9. html/css系列 BFC
  10. SuperBenchmarker一个用.NET编写的压测工具