• Linux进程间通信-eventfd


    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,关注最前沿的网络技术。

    原文阅读

  • 相关阅读:
    tcp/ip_properties_file
    tcp_ip/udp
    笔记1
    css样式使用_css
    常用的html标签总结_html
    利用sqlalchemy(ORM框架)连接操作mysql_mysql
    mysql基础命令_mysql
    redis使用_python
    RabitMQ使用_python
    后台管理页面2种常用模板_html
  • 原文地址:https://www.cnblogs.com/kekukele/p/12531824.html
Copyright © 2020-2023  润新知