对于linux libevent已经提供了一套锁机制,我们就不用自己在写一些锁相关的回掉函数(用evthread_set_lock_callbacks设置)供libevent使用,
我们在linux上使用锁机制的时候只要使用int evthread_use_pthreads(void) 开启使用多线程机制,那么锁的机制也会自动加入进来
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;
//将cbs结构内容保存在全局变量中evthread_lock_fns_ 用于后续锁的操作
//当然如果使用evthread_enable_lock_debuging()开启锁的debug模式,则此处的全局变量就是original_lock_fns_
evthread_set_lock_callbacks(&cbs);
//将cond_cbs结构内容保存到全局变量 evthread_cond_fns_用于后续条件变量的使用
//当然如果使用evthread_enable_lock_debuging()开启锁的debug模式,则此处的全局变量就是original_cond_fns_
evthread_set_condition_callbacks(&cond_cbs);
//将获取线程自身id的方式保存到evthread_id_fn_全局变量 用于后续线程获得自己的id
//对于linux来说此处是pthread_self()
evthread_set_id_callback(evthread_posix_get_id);
return 0;
}
那么接下来我们看下evthread_lock_callbacks结构体如下:
struct evthread_lock_callbacks {
int lock_api_version;//锁api的版本号 一般设置为 EVTHREAD_LOCK_API_VERSION
unsigned supported_locktypes;//锁的类型 EVTHREAD_LOCKTYPE_RECURSIVE递归锁 EVTHREAD_LOCKTYPE_READWRITE读写锁
void *(*alloc)(unsigned locktype);//分配一个锁的对象
void (*free)(void *lock, unsigned locktype);//释放一个锁的对象
int (*lock)(unsigned mode, void *lock); //对锁进行上锁
int (*unlock)(unsigned mode, void *lock); //解锁
};
在evthread_use_pthreads中我们初始化此结构如下
struct evthread_lock_callbacks cbs =
{
EVTHREAD_LOCK_API_VERSION, //首先版本设置为1
EVTHREAD_LOCKTYPE_RECURSIVE, //锁的类型为递归锁 允许一个线程多次访问
evthread_posix_lock_alloc, //锁对象的分配方式 看后面
evthread_posix_lock_free, //锁对象的释放方式 看后面
evthread_posix_lock, //上锁方式 看后面
evthread_posix_unlock //解锁方式 看后面
};
//对锁的分配初始化
static void *evthread_posix_lock_alloc(unsigned locktype)
{
pthread_mutexattr_t *attr = NULL;
//分配一个锁对象
pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t));
if (!lock)
return NULL;
//锁的类型 还记得evthread_use_pthreads中初始化的锁类型
if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE)
attr = &attr_recursive;
//设置锁的属性 并进行初始化
if (pthread_mutex_init(lock, attr)) {
mm_free(lock);
return NULL;
}
//返回锁的对象
return lock;
}
//对锁对象的销毁释放
static void evthread_posix_lock_free(void *lock_, unsigned locktype)
{
pthread_mutex_t *lock = lock_;
//销毁一个锁
pthread_mutex_destroy(lock);
mm_free(lock);
}
//对锁进行上锁
static int evthread_posix_lock(unsigned mode, void *lock_)
{
pthread_mutex_t *lock = lock_;
if (mode & EVTHREAD_TRY)
return pthread_mutex_trylock(lock);
else
return pthread_mutex_lock(lock);
}
//对锁进行解锁
static int evthread_posix_unlock(unsigned mode, void *lock_)
{
pthread_mutex_t *lock = lock_;
return pthread_mutex_unlock(lock);
}
接下来我们看看对条件变量的使用先看结构struct evthread_condition_callbacks如下:
struct evthread_condition_callbacks {
int condition_api_version; //条件变量API版本 设置为EVTHREAD_CONDITION_API_VERSION
void *(*alloc_condition)(unsigned condtype);//分配一个条件变量对象
void (*free_condition)(void *cond); //释放一个条件变量对象
int (*signal_condition)(void *cond, int broadcast);//发送信号等待此条件变量的线程
int (*wait_condition)(void *cond, void *lock,const struct timeval *timeout);//等待此条件变量的信号阻塞当前线程
};
然后看下在evthread_use_pthreads对此结构的初始化
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
};
//分配一个条件变量对象
static void * evthread_posix_cond_alloc(unsigned condflags)
{
pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t));
if (!cond)
return NULL;
//对条件变量初始化
if (pthread_cond_init(cond, NULL)) {
mm_free(cond);
return NULL;
}
返回条件变量对象
return cond;
}
//释放一个条件变量对象
static void evthread_posix_cond_free(void *cond_)
{
pthread_cond_t *cond = cond_;
pthread_cond_destroy(cond);
mm_free(cond);
}
//发送信号给 因等待此环境变量而组赛的线程
static int evthread_posix_cond_signal(void *cond_, int broadcast)
{
pthread_cond_t *cond = cond_;
int r;
if (broadcast)
r = pthread_cond_broadcast(cond);
else
r = pthread_cond_signal(cond);
return r ? -1 : 0;
}
//等待此环境变量 阻塞线程
static int evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
{
int r;
pthread_cond_t *cond = cond_;
pthread_mutex_t *lock = lock_;
//是否设置了超时时间
if (tv)
{
struct timeval now, abstime;
struct timespec ts;
evutil_gettimeofday(&now, NULL);
evutil_timeradd(&now, tv, &abstime);
ts.tv_sec = abstime.tv_sec;
ts.tv_nsec = abstime.tv_usec*1000;
//超时等待
r = pthread_cond_timedwait(cond, lock, &ts);
if (r == ETIMEDOUT)
return 1;
else if (r)
return -1;
else
return 0;
}
else
{
//一直等待
r = pthread_cond_wait(cond, lock);
return r ? -1 : 0;
}
}
我们在evthread_use_pthreads()中还有几个函数要介绍如下:
evthread_set_lock_callbacks(&cbs);
evthread_set_condition_callbacks(&cond_cbs);
evthread_set_id_callback(evthread_posix_get_id);
//设置锁的回掉
int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
{
//根据是否开启lock的debug模式返回不通的全局变量地址
//&original_lock_fns_ 或则和 &evthread_lock_fns_
//在程序开始若使用evthread_enable_lock_debuging()则会返回&original_lock_fns_ 否则返回&evthread_lock_fns_
//其中original_lock_fns_中存放用户定制的锁相关操作,而evthread_lock_fns_存放当前要操作的锁相关操作,
//如果先于evthread_use_pthreads()开启锁的调试功能evthread_lock_fns_中将存放debug_lock_xx 但最终还是会调用到original_lock_fns_中的锁操作
struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
//在编译libevent的时候没有使用--disable-debug-mode
#ifndef EVENT__DISABLE_DEBUG_MODE
if (event_debug_mode_on_) //是否开启了debug模式,用 event_enable_debug_mode() 开启debug模式
{
//在创建even_base的时候会将此值设置为1 , 如果为1 说明没有在使用event_base之前调用此函数 可能会引起错误
if (event_debug_created_threadable_ctx_) {
event_errx(1, "evthread initialization must be called BEFORE anything else!");
}
}
#endif
//传入的参数为空的话
if (!cbs)
{
//已经设置了相关锁的操作
if (target->alloc)
event_warnx("Trying to disable lock functions after ""they have been set up will probaby not work.");
//传入null值的话 会将锁的相关操作清空
memset(target, 0, sizeof(evthread_lock_fns_));
return 0;
}
//如果全局变量中已经存在了锁的相关操作
if (target->alloc)
{
/* Uh oh; we already had locking callbacks set up.*/
//设置的锁的操作是一个 直接返回0
if (target->lock_api_version == cbs->lock_api_version &&
target->supported_locktypes == cbs->supported_locktypes &&
target->alloc == cbs->alloc &&
target->free == cbs->free &&
target->lock == cbs->lock &&
target->unlock == cbs->unlock) {
/* no change -- allow this. */
return 0;
}
//锁一旦初始化 就不能被改变
event_warnx("Can't change lock callbacks once they have been "
"initialized.");
return -1;
}
//将锁的相关操作保存到全局变量中
if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
memcpy(target, cbs, sizeof(evthread_lock_fns_));
return event_global_setup_locks_(1); //主要分配一些全局锁 看后面介绍
}
else
{
return -1;
}
}
//设置环境变量相关操作的回掉
int evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
{
//根据是否开启lock的debug模式返回不通的全局变量地址
//&original_cond_fns_ 或者 &evthread_cond_fns_;
//在程序开始若使用evthread_enable_lock_debuging()则会返回&original_cond_fns_ 否则返回&evthread_cond_fns_
struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
//在编译libevent的时候没有使用--disable-debug-mode
#ifndef EVENT__DISABLE_DEBUG_MODE
if (event_debug_mode_on_) {//是否开启了debug模式,用 event_enable_debug_mode() 开启debug模式
//在创建even_base的时候会将此值设置为1 , 如果为1 说明没有在使用event_base之前调用此函数 可能会引起错误
if (event_debug_created_threadable_ctx_) {
event_errx(1, "evthread initialization must be called BEFORE anything else!");
}
}
#endif
//传入的参数为空的话 直接将全局变量中的内容清空
if (!cbs) {
if (target->alloc_condition)
event_warnx("Trying to disable condition functions "
"after they have been set up will probaby not "
"work.");
memset(target, 0, sizeof(evthread_cond_fns_));
return 0;
}
//若设置过条件变量。并且条件变量的类型不是同一个 则不允许再次设置
if (target->alloc_condition)
{
/* Uh oh; we already had condition callbacks set up.*/
if (target->condition_api_version == cbs->condition_api_version &&
target->alloc_condition == cbs->alloc_condition &&
target->free_condition == cbs->free_condition &&
target->signal_condition == cbs->signal_condition &&
target->wait_condition == cbs->wait_condition) {
/* no change -- allow this. */
return 0;
}
event_warnx("Can't change condition callbacks once they "
"have been initialized.");
return -1;
}
//将条件变量的相关操作保存到全局变量中
if (cbs->alloc_condition && cbs->free_condition &&
cbs->signal_condition && cbs->wait_condition)
{
memcpy(target, cbs, sizeof(evthread_cond_fns_));
}
//如果开启了lock debug模式 evthread_cond_fns_全局变量则不会被设置
//在后面会用到它, 所以此处也进行初始化
if (evthread_lock_debugging_enabled_)
{
evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
evthread_cond_fns_.free_condition = cbs->free_condition;
evthread_cond_fns_.signal_condition = cbs->signal_condition;
}
return 0;
}
//设置线程获得自己id的方式 保存到全局变量evthread_id_fn_中linux上用
//pthread_self()获得线程id
void evthread_set_id_callback(unsigned long (*id_fn)(void))
{
evthread_id_fn_ = id_fn;
}
在上面介绍evthread_set_lock_callbacks()的时候我们最后留了一个函数event_global_setup_locks_没有介绍,接下来我们看看他是干什么的
//下面函数安装一些全局锁
int event_global_setup_locks_(const int enable_locks)
{
//在编译libevent的时候没有使用--disable-debug-mode
#ifndef EVENT__DISABLE_DEBUG_MODE
//根据前面锁对象的分配方式分配一个 锁对象存储到event_debug_map_lock_中 这个锁用于log中,在log开启后会有个hash表用于存放所有安装的
//事件,此锁就是用于事件从hash中的删除和添加, 至于为啥要存储事件,此处不在展开
EVTHREAD_SETUP_GLOBAL_LOCK(event_debug_map_lock_, 0);
#endif
//分配一个全局锁对象 evsig_base_lock 用于添加删除删除信号事件
if (evsig_global_setup_locks_(enable_locks) < 0)
return -1;
//对于linux此处直接返回0
if (evutil_global_setup_locks_(enable_locks) < 0)
return -1;
//对于linx初始化一个全局锁对象 用于随机数的获取
if (evutil_secure_rng_global_setup_locks_(enable_locks) < 0)
return -1;
return 0;
}