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);
- 如果計數器中的值大於0:
- 設置了
EFD_SEMAPHORE
標志位,則返回1,且計數器中的值也減去1。 - 沒有設置
EFD_SEMAPHORE
標志位,則返回計數器中的值,且計數器置0。
- 如果計數器中的值為0:
- 設置了
EFD_NONBLOCK
標志位就直接返回-1。 - 沒有設置
EFD_NONBLOCK
標志位就會一直阻塞直到計數器中的值大於0。
寫操作
向計數器中寫入值。
int eventfd_write(int fd, eventfd_t value);
-
如果寫入值的和小於0xFFFFFFFFFFFFFFFE,則寫入成功
-
如果寫入值的和大於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,關注最前沿的網絡技術。