linux的epoll_wait以及epoll_ctl是否線程安全?
01-08
場景:
線程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 最差的用戶體驗是什麼?
※可以將一個網頁應用「打包」成一個桌面應用嗎?