写在前面:
这个源码是分析libevent-2.0.20-stable, 并非最新版本的libevent,作者并没有全看源码,在这里会推荐以下参考的一些网站,也欢迎大家在不足的地方提出来进行讨论。
锁
libevent的内部实现不需要多线程,为此我们在libevent的源码中也看不到有关线程的接口。但是我们很有可能在某个多线程程序中使用libevent,那么就需要保证线程共享的结构体是线程安全的,为此libevent提供了锁和条件变量来确保线程的同步。
libevent的结构体在多线程下通常有三种方式:
-
某些结构体只能使用在单线程:同时在多个线程中使用它们总是不安全的。
-
某些结构具有可选择的锁: 可以告知libevent是否需要在多个线程中使用每个对象。
-
某些结构体总是锁定的:如果libevent在支持锁的配置下运行,在多线程中使用它们总是安全的。
如果想要开启多线程模式,需要调用eventhread_use_pthreads()函数
int evthread_use_pthreads(void) { struct evthread_lock_callbacks cbs = { EVTHREAD_LOCK_API_VERSION, EVTHREAD_LOCKTYPE_RECURSIVE, evthread_posix_lock_alloc, evthread_posix_lock_free, evthread_posix_lock, evthread_posix_unlock }; struct evthread_condition_callbacks cond_cbs = { EVTHREAD_CONDITION_API_VERSION, evthread_posix_cond_alloc, evthread_posix_cond_free, evthread_posix_cond_signal, evthread_posix_cond_wait }; /* Set ourselves up to get recursive locks. */ if (pthread_mutexattr_init(&attr_recursive)) return -1; if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE)) return -1; evthread_set_lock_callbacks(&cbs); evthread_set_condition_callbacks(&cond_cbs); evthread_set_id_callback(evthread_posix_get_id); return 0; }
接下来我们就针对这个函数,自顶向下看看源码的实现,首先我们来看看锁回调结构体的实现
struct evthread_lock_callbacks { int lock_api_version; //版本号,默认设置为宏EVTHREAD_LOCK_API_VERSION unsigned supported_locktypes; //支持的锁类型,有普通锁,递归锁,读写锁三种 //分配一个锁变量(指针类型),因为不同的平台锁变量是不同的类型 //所以用这个通用的void*类型 void *(*alloc)(unsigned locktype); void (*free)(void *lock, unsigned locktype); int (*lock)(unsigned mode, void *lock); int (*unlock)(unsigned mode, void *lock); };
第一个元素是api_version,但是似乎在libevent中,都只有一个版本被宏定义成了1
#define EVTHR