linux網路程式設計 eventfd

2021-07-11 07:54:33 字數 2719 閱讀 8825

eventfd 在核心版本,2.6.22以後有效。檢視核心版本可以用命令 uname -r。

eventfd類似於管道的概念,可以實現執行緒間的事件通知,類似於pipe。而eventfd 是乙個比 pipe 更高效的執行緒間事件通知機制,一方面它比 pipe 少用乙個 file descriper,節省了資源;另一方面,eventfd 的緩衝區管理也簡單得多,全部「buffer」一共只有8位元組,不像pipe那樣可能有不定長的真正buffer。

eventfd的緩衝區大小是sizeof(uint64_t)也就是8位元組,它是乙個64位的計數器,寫入遞增計數器,讀取將得到計數器的值,並且清零。

涉及api:

#include int eventfd(unsigned int initval, int flags);
這個函式會建立乙個事件物件 (eventfd object), 用來實現程序(執行緒)間的等待/通知(wait/notify) 機制. 核心會為這個物件維護乙個64位的計數器(uint64_t)。

並且使用第乙個引數(initval)初始化這個計數器。呼叫這個函式就會返回乙個新的檔案描述符(event object)。2.6.27版本開始可以按位設定第二個引數(flags)。

flags 有如下的一些巨集可以使用:

efd_nonblock:功能同open(2) 的o_nonblock,設定物件為非阻塞狀態,如果沒有設定這個狀態的話,read(2)讀eventfd,並且計數器的值為0 就一直堵塞在read呼叫當中,要是設定了這個標誌, 就會返回乙個 eagain 錯誤(errno = eagain)。效果也如同 額外呼叫select(2)達到的效果。

efd_cloexec顧名思義是在執行 exec() 呼叫時關閉檔案描述符,防止檔案描述符洩漏給子程序。

如果是2.6.26或之前版本的核心,flags 必須設定為0。

建立這個物件後,可以對其做如下操作。

write 將緩衝區寫入的8位元組整形值加到核心計數器上。

read 讀取8位元組值, 並把計數器重設為0. 如果呼叫read的時候計數器為0, 要是eventfd是阻塞的, read就一直阻塞在這裡,否則就得到 乙個eagain錯誤。

如果buffer的長度小於8那麼read會失敗, 錯誤**被設定成 einval。

close 當不需要eventfd的時候可以呼叫close關閉, 當這個物件的所有控制代碼都被關閉的時候,核心會釋放資源。 為什麼不是close就直接釋放呢, 如果呼叫fork 建立

程序的時候會複製這個控制代碼到新的程序,並繼承所有的狀態。

(ps:也就是說,在write之後沒有read,但是又write新的資料,那麼讀取的是這兩次的8個位元組的和,在read之後再write,可以完成read和write之間的互動)

下面看乙個簡單的eventfd的示例:

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

#define handle_error(msg) \

do while (0)

intmain(int argc, char *argv)

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

exit(exit_success);

}else //parent

}

輸出:

解釋:這個例子很簡單,建立乙個eventfd用於父子程序之間通訊,子程序寫入資料,然後父程序讀取。例子並沒有什麼實際意義。

我們再看乙個稍微複雜一點的例子,使用epoll和eventfd:

#include #include #include #include #include #include #include #include #define epoll_max_num 10

#define handle_error(msg) \

do while (0)

int efd = -1;

void *read_thread(void *arg)

ep_fd = epoll_create(1024);

if (ep_fd < 0)

} while (1)

else if (events[i].events & epollerr)

else */

if (events[i].events & epollin)

else}}

} else if (ret == 0)

else

}}int main(int argc, char *argv)

ret = pthread_create(&pid, null, read_thread, null);

if (ret < 0)

for (i = 0; i < 5; i++)

sleep(1); }

printf("write_end\n");

pthread_join(pid, null);

close(efd);

return 0;

}

Linux網路程式設計

linux網路程式設計 當然,我們現在,將要開始編寫的第乙個網路程式,雖然非常簡單,但是卻可以很 清楚的說明大部分編寫網路程式需要的基本概念,好了先讓我們看看網路程式的tcp服 務器端的編寫步驟 1.和伺服器的步驟一樣。2.通過設定套介面位址結構,我們說明,客戶端要與之通訊的伺服器的ip位址和 埠。...

linux 網路程式設計

當然,我們現在,將要開始編寫的第乙個網路程式,雖然非常簡單,但是卻可以很 清楚的說明大部分編寫網路程式需要的基本概念,好了先讓我們看看網路程式的tcp服 務器端的編寫步驟 現在讓我們來看看網路程式客戶端的程式設計步驟 以上的步驟,是比較普遍的,我們可以從中看出,編寫網路程式是很有意思的,同 時,也不...

linux 網路程式設計

套接字程式設計 struct sockaddr unsigned short sa family 位址協議,ipv4 tcp ip af inet,ipv6 af inet6 char sa data 14 14位元組的位址協議 struct sockaddr in unsigned short s...