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,關注最前沿的網絡技術。

原文閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM