Linux進程間通訊-eventfd

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

建立方法

#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
複製代碼

建立的時候能夠傳入一個計數器的初始值initval。 第二個參數flags在linux 2.6.26以前的版本是沒有使用的,必須初始化爲0,在2.6.27以後的版本flag才被使用。ios

EFD_CLOEXEC(2.6.27~):c++

A copy of the file descriptor created by eventfd() is inherited by the child produced by fork(2). The duplicate file descriptor is associated with the same eventfd object. File descriptors created by eventfd() are preserved across execve(2), unless the close-on-exec flag has been set.bash

eventfd()會返回一個文件描述符,若是該進程被fork的時候,這個文件描述符也會複製過去,這時候就會有多個的文件描述符指向同一個eventfd對象,若是設置了EFD_CLOEXEC標誌,在子進程執行exec的時候,會清除掉父進程的文件描述符less

EFD_NONBLOCK(2.6.27~): 就如它字面上的意思,若是沒有設置了這個標誌位,那read操做將會阻塞直到計數器中有值。若是沒有設置這個標誌位,計數器沒有值的時候也會當即返回-1;ui

EFD_SEMAPHORE(2.6.30~): 這個標誌位會影響read操做,具體能夠看read方法中的解釋spa

提供的方法

read: 讀取計數器中的值code

  • 若是計數器中的值大於0
    • 設置了EFD_SEMAPHORE標誌位,則返回1,且計數器中的值也減去1。
    • 沒有設置EFD_SEMAPHORE標誌位,則返回計數器中的值,且計數器置0。
  • 若是計數器中的值爲0
    • 設置了EFD_NONBLOCK標誌位就直接返回-1。
    • 沒有設置EFD_NONBLOCK標誌位就會一直阻塞直到計數器中的值大於0。

write: 向計數器中寫入值對象

  • 若是寫入值的和小於0xFFFFFFFFFFFFFFFE,則寫入成功
  • 若是寫入值的和大於0xFFFFFFFFFFFFFFFE
    • 設置了EFD_NONBLOCK標誌位就直接返回-1。
    • 若是沒有設置EFD_NONBLOCK標誌位,則會一直阻塞知道read操做執行

close: 關閉文件描述符進程

一個小Demo

#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);
}
複製代碼

上面的程序中咱們建立了一個eventfd,並將它的文件描述符保存在efd中,而後調用eventfd_write向計數器中寫入數字2,而後調用eventfd_read讀取計數器中的值並打印處理,最後關閉eventfd。 運行結果:

count=2
複製代碼

屢次read和write

#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream>

int main() {
    int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    eventfd_write(efd, 2);
    eventfd_write(efd, 3);
    eventfd_write(efd, 4);
    eventfd_t count;
    int read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    close(efd);
}
複製代碼

運行結果:

read_result=0
count=9
read_result=-1
count=9
複製代碼

從運行結果咱們能夠看出當屢次調用eventfd_write的時候,計數器一直在累加,可是eventfd_read只需調用一次就能夠將計數器中的數取出來,若是再次調用eventfd_read將會返回失敗。

EFD_NONBLOCK標誌位的做用

#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream>

int main() {
    int efd = eventfd(0, EFD_CLOEXEC);
    eventfd_write(efd, 2);
    eventfd_write(efd, 3);
    eventfd_write(efd, 4);
    eventfd_t count;
    int read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    close(efd);
}
複製代碼

運行結果:

read_result=0
count=9
複製代碼

和前一個運行結果直接返回-1相比,若是去掉EFD_NONBLOCK標誌位,程序會在計數器沒有值的狀況下一直阻塞在eventfd_read方法。

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);
    eventfd_t count;
    int read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    read_result = eventfd_read(efd, &count);
    std::cout << "read_result=" << read_result << std::endl;
    std::cout << "count=" << count << std::endl;
    close(efd);
}
複製代碼

運行結果:

read_result=0
count=1
read_result=0
count=1
read_result=-1
count=1
複製代碼

能夠看到設置了EFD_SEMAPHORE後,每次讀取到的值都是1,且read後計數器也遞減1。

相關文章
相關標籤/搜索