Libevent 的多线程操作

时间:2023-03-09 02:14:11
Libevent 的多线程操作

起因是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会乱掉()