目录
以下源码均基于libevent-2.0.21-stable。
libevent中,使用了很多函数,而这么多的函数并不是所有都是对用户开放的,这一些函数声明都放在include文件夹下以供用户调用,而另一大部分不在其中的函数,则为libevent的内部调用函数。接下来要分析libevent的线程锁与条件变量,那么就先来看用户所能使用的接口有哪些,在include/event2文件夹下,可以看到一个thread.h的文件,因此就先从该文件入手开始分析。
锁与条件变量函数结构体
锁函数结构体
锁对应的结构体为evthread_lock_callbacks,其定义如下:
(thread.h)
struct evthread_lock_callbacks {
/** The current version of the locking API. Set this to
* EVTHREAD_LOCK_API_VERSION */
int lock_api_version;
/** Which kinds of locks does this version of the locking API
* support? A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and
* EVTHREAD_LOCKTYPE_READWRITE.
*
* (Note that RECURSIVE locks are currently mandatory, and
* READWRITE locks are not currently used.)
**/
unsigned supported_locktypes;
/** Function to allocate and initialize new lock of type 'locktype'.
* Returns NULL on failure. */ //以下都是函数指针
void *(*alloc)(unsigned locktype); //分配一个指定类型的锁,如果分配失败返回NULL
/** Funtion to release all storage held in 'lock', which was created
* with type 'locktype'. */
void (*free)(void *lock, unsigned locktype); //释放一个指定类型的锁,分配成功返回0,否则失败
/** Acquire an already-allocated lock at 'lock' with mode 'mode'.
* Returns 0 on success, and nonzero on failure. */
int (*lock)(unsigned mode, void *lock); //对一个已分配的锁进行加锁,锁的模式为read/write/try,获取成功返回0
/** Release a lock at 'lock' using mode 'mode'. Returns 0 on success,
* and nonzero on failure. */
int (*unlock)(unsigned mode, void *lock); //对一个已持有的锁进行解锁,解锁成功返回0;需指定锁的模式
};
锁结构体一共有6个变量,后面4个成员为函数指针,分别指向锁的分配(alloc)、释放(free)、上锁(lock)和解锁(unlock)四个函数,由此可见,libevent中的锁函数也是可以用户自己定制的。可以看到,这些锁函数中会用到的参数有锁变量lock、锁类型locktype以及锁模式mode,锁变量自然不必说,那么锁类型和锁模式是什么呢?
对于当前版本的libevent,thread.h中宏定义了WRITE、READ和TRY三种模式,以及RECURSIVE和READWRITE两种类型,如下所示。
#define EVTHREAD_WRITE 0x04 //用于读写锁中的写模式
#define EVTHREAD_READ 0x08 //用于读写锁中的读模式
#define EVTHREAD_TRY 0x10 //尝试加锁模式,如果获取不到锁也不用阻塞
#define EVTHREAD_LOCKTYPE_RECURSIVE 1 //递归锁,同一线程可以多次持有同一个锁,其他线程如果想获取该锁,需要持有线程进行加锁次数的解锁,此时递归锁才能被其他线程持有
#define EVTHREAD_LOCKTYPE_READWRITE 2 //读写锁,可以多个线程同时以读模式持有同一个锁,但是只能有一个线程以写模式持有该锁,如果该锁被写模式持有,那么其他线程也无法以读模式持有该锁
实际上还有默认的普通锁类型和模式,值为0,这里没有直接写出来,但是在后面的函数中会有所体现。
再回到前两个成员变量中。supported_locktypes就不用说了,就是指的锁的类型。lock_api_version从字面意义上将是锁的API版本,根据上面相关的英文说明,lock_api_version的位域以及目前锁类型(当前为递归锁和读写锁)的定义反映了当前版本的libevent所支持的锁类型,并且其中还提到,目前版本只使用了递归锁,没有使用读写锁,而当前的版本由宏定义EVTHREAD_LOCK_API_VERSION确定,其定义为
#define EVTHREAD_LOCK_API_VERSION 1
如何理解呢?根据我的理解,递归锁宏定义为1,读写锁为2,lock_api_version应当是其所支持的锁进行位或的结果就是,举个例子,如果只支持递归锁,那么lock_api_version就是1,与这里相对应;如果只支持读写锁,那么lock_api_version就应该是2;如果二者都支持,那么lock_api_version就应该为3了。这样,通过lock_api_version的位域也就能反映出当前版本支持哪些lock了。因此,如果后面拓展到其他类型的锁,那么锁宏定义应当为4、8....
设置自定义的锁函数
如同libevent的日志、错误处理以及内存管理函数一样,锁函数也可以进行定制,定制接口为evthread_set_lock_callbacks函数。其原型为:
int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);
原型很简单,传入一个锁函数结构体即可,调用该函数后,libevent中一旦需要使用锁的相关函数,那么就会自动调用传入的结构体中相对应的函数。该函数的实现在后面进行分析。
条件变量函数结构体
条件变量对应结构体为evthread_condition_callbacks,其定义如下:
struct evthread_condition_callbacks {
/** The current version of the conditions API. Set this to
* EVTHREAD_CONDITION_API_VERSION */
int condition_api_version;
/** Function to allocate and initialize a new condition variable.
* Returns the condition variable on success, and NULL on failure.
* The 'condtype' argument will be 0 with this API version.
*/
void *(*alloc_condition)(unsigned condtype); //分配并初始化一个条件变量,分配成功就返回这个条件变量,否则返回NULL,当前版本下的condtype为0
/** Function to free a condition varia