最近專案中使用了libev事件驅動庫,發現一個非常嚴重的問題,我的使用流程如下:
1.創建已知的ev_timer、ev_signal等watcher;
2.添加各種watcher到ev_type_start();
3.呼叫ev_run()驅動整個事件回圈運轉;
接下來,在使用程序中,會有新的定時或者其他需求,那么會動態的創建ev_timer等新的watcher;但是同樣呼叫ev_type_start()將watcher添加到已經ev_run()起來之后的event loop中,發現會無法立即生效,必須等event loop下一次事件觸發醒來之后,新進的watcher才能被真正有效。
經過內部原始碼調查,發現epoll_ctl()函式(Linux系統下)在ev_poll.c的epoll_modify()函式中呼叫,并在epoll_init()中初始化:
backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */
backend_modify = epoll_modify;
backend_poll = epoll_poll;
在整個event loop中,呼叫backend_modify介面的地方只有兩個:
[study@konishi libev]$ grep 'backend_modify' ./ -nR
./ev.c:2103: backend_modify (EV_A_ fd, anfd->events, 0);
./ev.c:2134: backend_modify (EV_A_ fd, o_events, anfd->events);
./ev_epoll.c:256: backend_modify = epoll_modify;
./ev_kqueue.c:168: backend_modify = kqueue_modify;
./ev_poll.c:135: backend_modify = poll_modify;
./ev_port.c:159: backend_modify = port_modify;
./ev_select.c:279: backend_modify = select_modify;
./ev_vars.h:66:VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev))
./ev_wrap.h:15:#define backend_modify ((loop)->backend_modify)
./ev_wrap.h:114:#undef backend_modify
即只在ev.c中的2103和2134中被呼叫,對應到ev.c中的靜態函式fd_reify()。這個函式也只在ev_run()中被呼叫一次,在embed_prepare_cb()中呼叫一次。embed_prepare_cb()就不說了,一般不會用到。
那問題來了,我們ev_run()在一個event loop中只能呼叫一次,呼叫多次會出錯例外:
test: ev.c:3579: ev_run: Assertion `("libev: ev_loop recursion during release detected", ((loop)->loop_done) != 0x80)' failed.
Aborted (core dumped)
但新的watcher又無法實施的添加的epoll機制中進行觀測,那就會導致加入新的watcher的事件到來的比eventloop更快,那么新的watcher就無法真正的進行實時監測了!
我自認對libev、libuv理解不夠深刻,這么強大和流行的事件庫,不可能沒考慮到這一點,留這么大的問題,因此請教大家如何利用libev、libuv實作動態watcher/事件的監控?
uj5u.com熱心網友回復:
謝邀,但是真不懂這些……
uj5u.com熱心網友回復:
沒人回答么?自己頂一下uj5u.com熱心網友回復:
沒看懂你的意思,只用過epoll,沒用過libeveent,epoll肯定是只有把監測點加到監控里面,epoll_wait事件才會回傳,我的理解是你是不是事件處理函式處理的時間太長了,一般情況下時間處理函式不能長的,如果長的話建議寫佇列,到佇列處理函式里面去處理,回呼函式盡量簡短,快速,還有一個取的時間數也不宜過多,轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/61088.html
標籤:網絡通信
