linux的epoll_wait以及epoll_ctl是否線程安全?

場景:

線程A是一個循環, 調用epoll_wait, 當有事件發生時執行對應的回調函數.

線程B不時會建立新的連接, 使用non-block的socket, connect後調用epoll_ctl將socket加入監聽.

線程A和線程B操作的是同一個epoll instance, 那麼是否有潛在的問題了?

根據man page對於epoll_wait的描述:

While one thread is blocked in a call to epoll_pwait(), it is
possible for another thread to add a file descriptor to the waited-
upon epoll instance. If the new file descriptor becomes ready, it
will cause the epoll_wait() call to unblock.

按照我的理解, 前面的做法不會有問題.

但是實際程序運行過程出現了這樣的現象: A線程正好從某次epoll_wait調用退出的時候, B線程加入的那個socket上發生的事件消失了(對應epoll_ctl返回值是0, 沒有顯示錯誤).

Google後得到的信息都是認為前述寫法不存在問題, 但是偶然在一個github的項目的issue看到不一樣的說法: epoll_wait() is oblivious to concurrent updates via epoll_ctl() · Issue #331 · cloudius-systems/osv · GitHub, 所以將原來的寫法改了, B線程不能直接調用epoll_ctl, 而是寫一個pipe喚醒A線程, 在A線程執行對應的操作. 改了之後bug沒再出現了.

所以, 是man page的說法有誤還是我理解有誤??


epoll_wait和epoll_ctl都是線程安全的, 前者帶acquire語意, 後者帶release語意, 換句話說, 如果epoll_wait後能拿到某個新fd的事件, 那麼對應的epoll_ctl前發生的內存修改都可見. 但在老版本內核中可能有bug, 比如[32/49] epoll: prevent missed events on EPOLL_CTL_MOD


用 pipe 或 eventfd 是常規的做法,我見過的網路庫都這麼做。


建議看看memcached的使用libevent方法


推薦閱讀:

有哪些 Linux 逆向相關的學習資料推薦?
Pwn2Own 有Unix/Linux系統的機器被攻破么?
Linux 為何不把圖形用戶界面寫入內核?
你認為 Linux 最差的用戶體驗是什麼?
可以將一個網頁應用「打包」成一個桌面應用嗎?

TAG:Linux | epoll | 多線程 | 線程安全 |