Linux進程間通訊-eventfd

eventfd是linux 2.6.22後系統提供的一個輕量級的進程間通訊的系統調用,eventfd經過一個進程間共享的64位計數器完成進程間通訊,這個計數器由在linux內核空間維護,用戶能夠經過調用write方法向內核空間寫入一個64位的值,也能夠調用read方法讀取這個值。linux

新建

建立一個eventfd對象,或者說打開一個eventfd的文件,相似普通文件的open操做。
該對象是一個內核維護的無符號的64位整型計數器。初始化爲initval的值。ios

#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,則寫入成功post

  2. 若是寫入值的和大於0xFFFFFFFFFFFFFFFEui

  • 設置了 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);
}

上述程序主要作了以下事情:code

  • 建立事件,初始計數器爲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,關注最前沿的網絡技術。

原文閱讀

相關文章
相關標籤/搜索