一起来感受下eventfd的魅力(一、eventfd使用介绍)-程序员宅基地

技术标签: 操作系统  eventfd  

一、函数介绍

       #include <sys/eventfd.h>

       int eventfd(unsigned int initval, int flags);

eventfd()函数可以创建一个被用户空间应用程序作为“等待/通知”机制使用的eventfd对象,或被内核用于通知用户空间应用程序事件消息。eventfd对象包含一个uint64_t类型计数器,由内核进行维护。该计数器通过参数interval进行初始化。

eventfd()函数返回一个文件描述符,这个fd用于对eventfd对象的引用。

第二个参数在Linux 2.6.30以后的版本没有再使用了,所以再使用该函数的时候必须置0.

函数执行成功返回值为一个新的eventfd文件描述符,否则为-1;

二、函数说明

        无论什么情况下,如果仅仅是用于发出信号事件,应用程序可以使用一个eventfd文件描述符来替换管道。而且内核使用eventfd文件描述符的开销要比管道低得多,而且一个eventfd文件描述符就可以满足要求。

        当我们在kernel中使用eventfd时,一个eventfd文件描述符就是一个由内核通向用户空间的桥梁。像KAIO(Kernel AIO)一样,向文件描述符发送信号以表示某些操作的完成。

        还有一个关键点就是,eventfd文件描述符与其他文件描述符一样,可以被select、poll、epoll监听。这就意味着一个应用程序可以同时监听传统文件是否就绪,也可以监听kernel所支持的eventfd接口文件。

        当前的eventfd计数器可以通过进程的/proc/[pid]/fdinfo来查看。

2.1 C库和kernel中实现的区别

有两个基础Linux系统调用,一个是eventfd(),一个是eventfd2()。前面一个系统调用函数的没有实现flags参数,后面一个系统调用函数则有对flags进行了实现。

2.2 glibc拓展功能

GNU C库定义了一个额外的类型和两个函数来对eventfd文件描述符读写细节进行抽象:

           typedef uint64_t eventfd_t;

           int eventfd_read(int fd, eventfd_t *value);
           int eventfd_write(int fd, eventfd_t value);

如上两个函数主要实现了对eventfd文件描述符的读写操作,成功返回0,反之为-1。

三、使用例子

3.1 代码案例

       #include <sys/eventfd.h>
       #include <unistd.h>
       #include <inttypes.h>           /* Definition of PRIu64 & PRIx64 */
       #include <stdlib.h>
       #include <stdio.h>
       #include <stdint.h>             /* Definition of uint64_t */

       #define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

       int
       main(int argc, char *argv[])
       {
           int efd;
           uint64_t u;
           ssize_t s;

           if (argc < 2) {
               fprintf(stderr, "Usage: %s <num>...\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           efd = eventfd(0, 0);
           if (efd == -1)
               handle_error("eventfd");

           switch (fork()) {
           case 0:
               for (int j = 1; j < argc; j++) {
                   printf("Child writing %s to efd\n", argv[j]);
                   u = strtoull(argv[j], NULL, 0);
                           /* strtoull() allows various bases */
                   s = write(efd, &u, sizeof(uint64_t));
                   if (s != sizeof(uint64_t))
                       handle_error("write");
               }
               printf("Child completed write loop\n");

               exit(EXIT_SUCCESS);

           default:
               sleep(2);

               printf("Parent about to read\n");
               s = read(efd, &u, sizeof(uint64_t));
               if (s != sizeof(uint64_t))
                   handle_error("read");
               printf("Parent read %"PRIu64" (%#"PRIx64") from efd\n", u, u);
               exit(EXIT_SUCCESS);

           case -1:
               handle_error("fork");
           }
       }

        这个例子只是官方给我们的如何使用eventfd的一个例子,并不涉及到user space和kernel space之间的事件通信。因此我们还需要继续调研如使用eventfd来实现kerne向user space发送事件消息。来感受eventfd真正的魅力。

3.2 案例编译执行

编译命令如下:

gcc eventfd_test.c -std=c99 -o eventfd_test

执行过程如下:


root@DESKTOP-TTJOEDD:~/workspace/01_code/00_demo# gcc eventfd_test.c -std=c99 -o eventfd_test
root@DESKTOP-TTJOEDD:~/workspace/01_code/00_demo# ls
eventfd_test  eventfd_test.c
root@DESKTOP-TTJOEDD:~/workspace/01_code/00_demo# ./eventfd_test 1 3 5 7 9
Child writing 1 to efd
Child writing 3 to efd
Child writing 5 to efd
Child writing 7 to efd
Child writing 9 to efd
Child completed write loop
Parent about to read
Parent read 25 (0x19) from efd

四、再来说说evenfd

        前半篇读起来或许有些生硬。实际上可以把eventfd理解为是Linux内核为用户空间应用程序提供了一种信号量机制,但相较于传统POSIX信号量的优势是,eventfd在内核中以文件形式存在,可以用于select/epoll监听以达到异步的目的,避免在没有事件时发生阻塞。

        我们再看下具体的使用方法。

4.1 read

读取计数器的值。

  • 如果计数器中的值大于0
    • 设置了EFD_SEMAPHORE标志位,则返回1,且计数器中的值减去1.
    • 没有设置EFD_SEMAPHORE标志位,则返回计数器中的值,且计数器设置为0.
  • 如果计数器中的值为0
    • 设置了EFD_NONBLOCK标志位就直接返回-1.
    • 没有设置EFD_NONBLOCK标志位就会一直阻塞直到计数器中的值大于0.

4.2 write

向计数器中写入值。

  • 如果写入的值和小于0xFFFFFFFFFFFFFFFE,则写入成功。
  • 如果写入的值和大于0xFFFFFFFFFFFFFFFE
    • 设置了EFD_NONBLOCK标志位就直接返回-1
    • 如果没有设置EFD_NONBLOCK标志位,则会一直阻塞直到read操作执行。

4.3 IO多路复用

epoll()/poll()/select(): 支持 IO 多路复用操作

4.4 close

关闭文件描述符

在下一篇博客中我们再来聊一聊,kernel如何使用eventfd向user space发送消息事件。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/huangyabin001/article/details/123842942

智能推荐

5G浪潮下,AI将会发生怎样的变化-程序员宅基地

文章浏览阅读254次。1 什么是5G5G 是指第五代移动通信技术,它相比4G网络在数据传输速度、容量和延迟方面都有很大的飞跃。在国际电信联盟(ITU)制定的5G 标准中,定义了5G 未来的三大应用场景:增强移动带宽(eMBB)、低时延高可靠通信(uRLLC)和大规模机器通信(mMTC)。说人话,就是:高速率:未来理论上10Gbps 的通讯速率,目前相比4G提升了约100倍低延时:1ms的超低延时,相比于4G网络..._云视频接入终端9060

计算机更新bios,win7bios升级教程_win7电脑主板bios升级的方法-程序员宅基地

文章浏览阅读933次。2019-10-25 17:35:37  浏览量:20172技嘉主板如何在线更新bios程序?bios是存储输入输出设备相关设置的程序,bios也是和软件一样,有版本的区别,bios版本不同,所能发挥的功能也有区别。bios程序能不能升级,需要查看主板官网有没有提供新版本的更新程序,如果有就可以升级。这边系统城小编教大家技嘉主板升级bios的方法。2016-07-21 13:50:35  浏览量:..._win7如何刷新bios

第86章、系统服务之TELEPHONY_SERVICE(从零开始学Android)-程序员宅基地

文章浏览阅读517次。  TelephonyManager类主要提供了一系列用于访问与手机通讯相关的状态和信息的get方法。其中包括手机SIM的状态和信息、电信网络的状态及手机用户的信息。在应用程序中可以使用这些get方法获取相关数据。 TelephonyManager类的对象可以通过Context.ge..._android telephony_service

富文本编译器_ogeditor-程序员宅基地

文章浏览阅读1.9k次。ogEditor 是一个在线的所见即所得的 HTML 编辑器,内置文件管理器支持。Redactor[Textarea - 富文本编辑器 ]Redactor 是一个 jQuery 的插件,实现在线所见即所得的 HTML 编辑器。界面简洁,加载速度快。不过不支持 IE6 浏览器,如果你不需要考虑 IE6 不妨试试。CuteEditor[Textarea - 富文本编_ogeditor

互动直播的技术细节和解决方案实践经验谈_webrtc连麦-程序员宅基地

文章浏览阅读4.4k次,点赞2次,收藏3次。互动直播系统介绍_webrtc连麦

js 获取DOM元素样式_js获取dom样式-程序员宅基地

文章浏览阅读7.8k次。 HTML的样式写入方法有:1、行内样式;2、内嵌样式;3、外联样式表。 行内样式:一般是用style写在dom元素上的,例如:&lt;div style='height:200px;'&gt;&lt;/div&gt;; 内嵌样式:一般是用style写在head标签内的。&lt;style type='text/css'&gt;&lt;/style&gt;; 外联样式:一般..._js获取dom样式

随便推点

ubuntu内核与驱动不兼容问题_ubuntu20内核冲突-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏3次。Ubuntu更新完NVIDIA驱动后,重启电脑进入不了系统,一直处于登录界面.后来重启电脑时发现我进入不了系统了,输入我的登录密码会发现屏幕一闪,然后又重新跳回到登录界面,就是进入了login loop的状态,我一开始在网上查,很多人说是什么.Xauthority的问题,我尝试了几乎所有办法都不行,所幸最后找到了问题所在,将Ubuntu NVIDIA驱动卸载再重新安装即可。造成这种问题的与原因是更_ubuntu20内核冲突

导出excel:下载模板时填充数据方法实现_excelexportutil模板列表填充-程序员宅基地

文章浏览阅读1.8k次。 /** * 导出excel * @param model * @param request * @param userAgent * @param id * @return */ @RequestMapping(value = "export.htm") ..._excelexportutil模板列表填充

多线程——这些锁策略(乐观悲观锁、读写锁、轻量级重量级锁、公平非公平锁、可重入锁)你知道吗?_读写锁连续加锁-程序员宅基地

文章浏览阅读1.7k次,点赞15次,收藏2次。各种锁策略1、乐观锁VS悲观锁2、读写锁3、重量级锁vs轻量级锁.4、挂起等待锁VS自旋锁5、公平锁Vs非公平锁6、可重入锁7、死锁的典型场景1、乐观锁VS悲观锁乐观锁: 世界大概率是和平的,多个线程竞争一 把锁的概率会很低.(效率高)悲观锁: 世界大概率是出问题的,多个线程竞争一 把锁的概率会很高,会付出更多的成本来进行锁冲突的处理(更安全)两种想法没有优劣之分,要根据具体场景来进行使用.2、读写锁把加锁操作分成了两种.a)读锁b)写锁读锁和读锁之间是没有互斥的(不存在锁竞争)读锁和写_读写锁连续加锁

OpenCV saturate_cast防溢出_opencv 点赋值 防止溢出-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏5次。saturate_cast函数在OpenCV中的作用是防数据溢出,我们在直接操作像素点的时候,如果数值结果是赋值或者超过了255的话,在图片中是没办法显示的,这就是防数据溢出的作用,那么什么时候会有数据溢出的风险呢,这种情况在图像卷积操作的时候比较常见。 下面我们举个栗子吧: 选择一个3*3的锐化作用的卷积核,设计如下: (0, -1, 0, -1, 5, -1,_opencv 点赋值 防止溢出

6、js控制,设置图片跟随窗口(主要是根据高度变化)大小变化,按比例缩放_前端图片大小随着高度而变化-程序员宅基地

文章浏览阅读2k次。html:&lt;div class="container"&gt; &lt;img src="https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1545633786675&amp;di=1b43ca4fe89c44cc06b026d21f646e91&amp;imgtype=0..._前端图片大小随着高度而变化

语音变速、变调方法汇总_sox 变调-程序员宅基地

文章浏览阅读1.2k次。介绍三种语音变速、变调方法:1. 变速变调;2. 变速不变调;3. 变调不变速。_sox 变调

推荐文章

热门文章

相关标签