起因是event_base 跨線程add/remove event 導致崩潰或者死循環。
據查:libvent 1.4.x是非線程安全的,要跨線程執行event_add,會有問題。
因此傳統做法是通過pipe來通知宿主線程執行event_add操作。
libevent 2.0.x通過線程鎖做到了線程安全,可以跨線程執行event_add。
需要在創建event_base之前調用evthread_use_pthreads(),需要添加event_pthread 庫,函數定義在event/thread.h
// 原理參照自 http://blog.chinaunix.net/uid-17260303-id-3342299.html
libevent關於多線程的使用需要在所有的初始化之前加evthread_use_pthreads()函數的原因:
evthread_use_pthreads()定義在evthread_pthread.c里面。在這個函數里,初始化了一個evthread_lock_callbacks對象 cbs,然后調用evthread_set_lock_callbacks(&cbs);來的對cbs這個evthread_lock_callbacks對象做操作。evthread_set_lock_callbacks定義在evthread.c里面。在這個函數里,其實就是將cbs的值賦值給了全局變量_evthread_lock_fns。
在定義了_EVENT_DISABLE_THREAD_SUPPORT的情況下
在add_event函數里面,libevent調用了EVBASE_ACQUIRE_LOCK這個宏。這個宏定義在evthread-internal.h, 同時EVBASE_ACQUIRE_LOCK這個宏又調用了EVLOCK_LOCK,EVLOCK_LOCK又調用了全局變量_evthread_lock_fns的lock成員。這個_evthread_lock_fns就是之前說過的那個。所以其實就是調用了evthread_use_pthreads()函數設置的_evthread_lock_fns這個結構體的lock成員。而這個lock成員函數,根據evthread_use_pthreads()函數里面設置的值,就是evthread_posix_lock函數,其中參數mode是0,參數_lock是base.th_base_lock。所以其實就是pthread_mutex_lock(base.th_base_lock)
在沒有定義_EVENT_DISABLE_THREAD_SUPPORT的情況下
在add_event函數里面,libevent調用了EVBASE_ACQUIRE_LOCK這個宏。這個宏定義在evthread-internal.h, 同時EVBASE_ACQUIRE_LOCK這個宏又調用了EVLOCK_LOCK,EVLOCK_LOCK又調用了函數_evthreadimpl_lock_lock(),參數mode是0,參數lock是base.th_base_lock。_evthreadimpl_lock_lock定義在evthread.c里面。在_evthreadimpl_lock_lock函數里面,會先判斷全局變量_evthread_lock_fns的lock存不存在。如果存在就調用_evthread_lock_fns的lock成員,相當於就是調用evthread_posix_lock函數了,就和定義了_EVENT_DISABLE_THREAD_SUPPORT的情況一樣了。如果不存在就什么都不干,返回0。
因為我的環境里面是沒有定義_EVENT_DISABLE_THREAD_SUPPORT的,所以如果不在開始的時候調用evthread_use_pthreads(),那么全局變量_evthread_lock_fns就沒有被賦值,他的lock成員自然也就是NULL了。所以,EVBASE_ACQUIRE_LOCK宏其實什么都沒干,也就沒有加鎖,所以在多個線程里面add_event會亂掉()