最高效的進 線 程間通訊機制 eventfd

2021-07-25 05:41:03 字數 3396 閱讀 8553

我們常用的程序(執行緒)間通訊機制有管道,訊號,訊息佇列,訊號量,共享記憶體,socket等等,其中主要作為程序(執行緒)間通知/等待的有管道pipe和socketpair。執行緒還有特別的condition。

今天來看乙個liunx較新的系統呼叫,它是從linux 2.6.27版本開始增加的,主要用於程序或者執行緒間的通訊(如通知/等待機制的實現)。

首先來看一下函式原型:

#include int eventfd(unsigned int initval, int flags);
下面是它man手冊中的描述,我照著翻譯了一遍(我英語四級434,你們要是懷疑下文的話,可以直接去man eventfd ^^):

eventfd()建立了乙個"eventfd object",能在使用者態用做事件wait/notify機制,通過核心取喚醒使用者態的事件。這個物件儲存了乙個核心維護的uint64_t型別的整型counter。這個counter初始值被引數initval指定,一般初值設定為0。

它的標記可以有以下屬性:

efd_cloecex,efd_nonblock,efd_semaphore。

在linux直到版本2.6.26,這個flags引數是沒用的,必須指定為0。

它返回了乙個引用eventfd object的描述符。這個描述符可以支援以下操作:

read:如果計數值counter的值不為0,讀取成功,獲得到該值。如果counter的值為0,非阻塞模式,會直接返回失敗,並把errno的值指紋einval。如果為阻塞模式,一直會阻塞到counter為非0位置。

write:會增加8位元組的整數在計數器counter上,如果counter的值達到0xfffffffffffffffe時,就會阻塞。直到counter的值被read。阻塞和非阻塞情況同上面read一樣。

close:這個操作不用說了。

重點是支援這個:

poll(2), select(2) (and similar)

the returned file descriptor supports poll(2) (and analogously epoll(7)) and select(2), as follows:

*  the file descriptor is readable (the select(2) readfds argument; the poll(2) pollin flag) if the  counter  has  a

value greater than 0.

*  the  file descriptor is writable (the select(2) writefds argument; the poll(2) pollout flag) if it is possible to

write a value of at least "1" without blocking.

*  if an overflow of the counter value was detected, then select(2) indicates the  file  descriptor  as  being  both

readable  and  writable,  and  poll(2)  returns a pollerr event.  as noted above, write(2) can never overflow the

counter.  however an overflow can occur if 2^64 eventfd "signal posts" were performed by the kaio subsystem (the‐

oretically possible, but practically unlikely).  if an overflow has occurred, then read(2) will return that maxi‐

mum uint64_t value (i.e., 0xffffffffffffffff).

the eventfd file descriptor also supports the other file-descriptor multiplexing apis: pselect(2) and ppoll(2).

它的核心**實現是這樣子的:

int eventfd_signal(struct eventfd_ctx *ctx, int n)

本質就是做了一次喚醒,不用read,也不用write,與eventfd_write的區別是不用阻塞。

說了這麼多,我們來看乙個例子,理解理解其中的含義:

#include #include #include #include #include /* definition of uint64_t */

#define handle_error(msg) \

do while (0)

intmain(int argc, char *argv)

efd = eventfd(0, 0);

if (efd == -1)

handle_error("eventfd");

switch (fork())

printf("child completed write loop\n");

exit(exit_success);

default:

sleep(2);

printf("parent about to read\n");

s = read(efd, &u, sizeof(uint64_t));

if (s != sizeof(uint64_t))

handle_error("read");

printf("parent read %llu (0x%llx) from efd\n",

(unsigned long long) u, (unsigned long long) u);

exit(exit_success);

case -1:

handle_error("fork");

}}

輸出:

$ ./a.out 1 2 4 7 14

child writing 1 to efd

child writing 2 to efd

child writing 4 to efd

child writing 7 to efd

child writing 14 to efd

child completed write loop

parent about to read

parent read 28 (0x1c) from efd

注意:這裡用了sleep(2)保證子程序迴圈寫入完畢,得到的值就是綜合28。如果不用sleep(2)來保證時序,當子程序寫入乙個值,父程序會立馬從eventfd讀出該值。

程序 執行緒間通訊機制

管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的程序間使用。程序的親緣關係通常是指父子程序。有名管道也是半雙工的通訊方式,但是它允許無親緣關係的程序間通訊。訊號量是乙個計數器,可以用來控制多個程序對共享資源的訪問。它常作為一種鎖機制,防止某程序正在訪問共享資源時,其他程序也訪問...

執行緒間通訊 等待喚醒機制

執行緒間通訊 其實就是多個執行緒在操作同乙個資源,但是操作的動作不同 class res2 class input2 implements runnable public void run catch interruptedexception e if x 0 else x x 1 2 r.flag...

執行緒間的通訊 等待喚醒機制

執行緒間的通訊 同步執行緒必須滿足兩個條件 一 兩個或兩個以上的執行緒 二 都使用同乙個鎖物件 題目描述 首先有乙個資源池 resource 輸入執行緒 input 不斷往資源池內新增內容,輸出執行緒 output 不斷往外輸出內容 並且兩個執行緒需要同步。需要的結果是,輸入執行緒輸入乙個內容,然後...