• eventfd


    1. 

    1. #include
    2. int eventfd(unsigned int initval, int flags); //创建eventfd

    参数含义:
    initval:创建eventfd时它所对应的64位计数器的初始值;
    flags:eventfd文件描述符的标志,可由三种选项组成:EFD_CLOEXEC、EFD_NONBLOCK和EFD_SEMAPHORE。
    EFD_CLOEXEC:表示返回的eventfd文件描述符在fork后exec其他程序时会自动关闭这个文件描述符;
    EFD_NONBLOCK:设置返回的eventfd非阻塞;
    EFD_SEMAPHORE表:表示将eventfd作为一个信号量来使用。
     

    2.

    例子

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. /* Definition of uint64_t */
    7. #define handle_error(msg) \
    8. do \
    9. { \
    10. perror(msg); \
    11. exit(EXIT_FAILURE); \
    12. } while (0)
    13. int main(int argc, char *argv[])
    14. {
    15. int efd, j;
    16. uint64_t u;
    17. ssize_t s;
    18. if (argc < 2)
    19. {
    20. fprintf(stderr, "Usage: %s ...\n", argv[0]);
    21. exit(EXIT_FAILURE);
    22. }
    23. efd = eventfd(0, 0);
    24. if (efd == -1)
    25. handle_error("eventfd");
    26. switch (fork())
    27. {
    28. case 0:
    29. for (j = 1; j < argc; j++)
    30. {
    31. printf("Child writing %s to efd\n", argv[j]);
    32. u = strtoull(argv[j], NULL, 0);
    33. /* strtoull() allows various bases */
    34. s = write(efd, &u, sizeof(uint64_t)); // 每次写入会累加
    35. if (s != sizeof(uint64_t))
    36. handle_error("write");
    37. }
    38. printf("Child completed write loop\n");
    39. exit(EXIT_SUCCESS);
    40. default:
    41. sleep(2);
    42. printf("Parent about to read\n");
    43. s = read(efd, &u, sizeof(uint64_t));
    44. if (s != sizeof(uint64_t))
    45. handle_error("read");
    46. printf("Parent read %llu (0x%llx) from efd\n",
    47. (unsigned long long)u, (unsigned long long)u);
    48. exit(EXIT_SUCCESS);
    49. case -1:
    50. handle_error("fork");
    51. }
    52. }

    其他用法,

    一个消费者,多个生产的时候,

    1. producer:
    2. // 投递请求到链表
    3. list_add( global_list, request )
    4. // 唤醒消费者处理
    5. write(eventfd, &cnt /* 1 */ , 8)
    1. consumer
    2. // 添加 eventfd 到监听池
    3. epoll_ctl(ep, EPOLL_CTL_ADD, eventfd, &ee);
    4. loop:
    5. // 等待唤醒
    6. epoll_wait(ep, ... );
    7. // 读取新添加到列表里的元素个数,并且进行处理;
    8. n = read(eventfd, ... )
    9. // 遍历链表处理
    10. for each global_list:

    一个消费者,一个生产者

    1. #include
    2. #include
    3. #include
    4. #include
    5. int fd;
    6. uint64_t buffer;
    7. void threadFunc(void) //线程函数
    8. {
    9. int t;
    10. while(1)
    11. {
    12. t = read(fd,&buffer,sizeof(buffer)); //阻塞等待fd可读,及通知事件发生
    13. if(sizeof(buffer) < 8)
    14. {
    15. printf("buffer错误\n");
    16. }
    17. printf("t = %llu buffer = %llu\n",t,buffer);
    18. if(t == 8)
    19. {
    20. printf("唤醒成功\n");
    21. }
    22. }
    23. }
    24. int main(void)
    25. {
    26. uint64_t buf = 1;
    27. int ret;
    28. pthread_t tid;
    29. if((fd = eventfd(0,0)) == -1) //创建事件驱动的文件描述符
    30. {
    31. printf("创建失败\n");
    32. }
    33. //创建线程
    34. if(pthread_create(&tid,NULL,threadFunc,NULL) < 0)
    35. {
    36. printf("线程创建失败\n");
    37. }
    38. while(1)
    39. {
    40. ret = write(fd,&buf,sizeof(buf)); //通过往fd里写东西来进行事件通知
    41. if(ret != 8)
    42. {
    43. printf("写错误\n");
    44. }
    45. sleep(2); //没2s通知一次
    46. }
    47. return 0;
    48. }

    用于在进程间传递事件信号,与 pipe 相比,eventfd 具有更高的性能和更好的可扩展性,可以支持更多的并发连接。

    在 Nginx 的事件模块中,当系统支持 eventfd 时,会启用 eventfd 作为唤醒机制,来代替之前使用 pipe 和 signal 的方式。使用 eventfd 可以避免 signal 的问题(如慢 syscalls 可能被中断、signal 处理可能会导致竞争和死锁等),且相比于使用 pipe 的方式,可以减少内存消耗和增加性能。

    eventfd不支持非亲缘关系进程之间的事件通知,因为 eventfd 使用的内核数据结构属于文件描述符表,而文件描述符表只能在同一进程内共享。

    无名信号量也不支持非亲缘关系的进程

    eventfd 和 条件变量.和信号量都差不多, 都是可以通知唤醒, 

    .如果只是简单的事件通知或计数,且不需要对共享资源进行保护,那么 eventfd 可能更为高效

    如果需要等待特定条件满足或对共享资源进行保护,那么条件变量可能更适合

    使用信号量需要进行加锁、解锁和等待操作,这可能引入一定的开销。尤其是在竞争激烈的场景下,频繁地获取和释放信号量可能导致性能下降

    fcnt 给文件加读写锁,也可以用于进程间的同步

  • 相关阅读:
    Apollo与TypeScript:强大类型检查在前端开发中的应用
    学编程:Python入门考级必备[7]
    VS|vs2017跨平台编译linux&&C++Console&&QtGUI
    「 安全工具介绍 」软件成分分析工具Black Duck,业界排名TOP 1的SCA工具
    问道管理:历史市净率在哪看?
    sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步
    第十四届蓝桥杯校模拟赛-编程大题详解+代码(二)
    MySQL分页查询的5种方法
    Linux搭建Zookeeper伪集群详解
    780. 到达终点;2360. 图中的最长环;1871. 跳跃游戏 VII
  • 原文地址:https://blog.csdn.net/qixiang2013/article/details/133798717