参考libevent官方提供的文档: http://www.wangafu.net/~nickm/libevent-book/Ref1_libsetup.html

这一篇主要翻译libevent多线程的使用接口和文档。

As you probably know if you’re writing multithreaded programs, it isn’t always safe to access the same data from multiple threads at the same time.

Libevent structures can generally work three ways with multithreading.

  • Some structures are inherently single-threaded: it is never safe to use them from more than one thread at the same time.

  • Some structures are optionally locked: you can tell Libevent for each object whether you need to use it from multiple threads at once.

  • Some structures are always locked: if Libevent is running with lock support, then they are always safe to use from multiple threads at once.

当你编写多线程程序的时候,多个线程访问同一块数据并不安全。对于多线程libevent通常采取以下三种方式工作,

1 一些结构内不是单线程的,多线程同时访问这个结构是不安全的。

2一些结构内部是选择性加锁的,你需要通知libevent,对于每个对象你是否采用多线程的方式使用它。

3一些结构总是加锁的,如果libevent设置了加锁的模式,采用多线程方式是安全的。

To get locking in Libevent, you must tell Libevent which locking functions to use. You need to do this before you call any Libevent function

that allocates a structure that needs to be shared between threads.

If you are using the pthreads library, or the native Windows threading code, you’re in luck. There are pre-defined functions that will set

Libevent up to use the right pthreads or Windows functions for you.

如果要使用libevent多线程锁的功能,需要开辟一个线程共享的结构,如果您使用windows或者linux提供的pthread库,libevent已经定义好了。

#ifdef WIN32
int evthread_use_windows_threads(void);
#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
#endif
#ifdef _EVENT_HAVE_PTHREADS
int evthread_use_pthreads(void);
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED
#endif

libevent针对win32平台定义了evthread_use_windows_threads,

libevent针对Linux thread库 定义了evthread_use_pthreads

evthread_use_pthread函数是这样的

int
evthread_use_pthreads(void)
{
//pthread lock callback结构体对象
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 -;
if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
return -;
//将cbs的属性设置到全局变量中,分为调试和正常模式
evthread_set_lock_callbacks(&cbs);
//同样将cond_cbs设置到全局变量
evthread_set_condition_callbacks(&cond_cbs);
//设置线程id到全局变量
evthread_set_id_callback(evthread_posix_get_id);
return ;
}

这几个结构体如下

#define EVTHREAD_WRITE  0x04
#define EVTHREAD_READ 0x08
#define EVTHREAD_TRY 0x10 #define EVTHREAD_LOCKTYPE_RECURSIVE 1
#define EVTHREAD_LOCKTYPE_READWRITE 2 #define EVTHREAD_LOCK_API_VERSION 1 struct evthread_lock_callbacks {
int lock_api_version;
unsigned supported_locktypes;
void *(*alloc)(unsigned locktype);
void (*free)(void *lock, unsigned locktype);
int (*lock)(unsigned mode, void *lock);
int (*unlock)(unsigned mode, void *lock);
}; int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *); void evthread_set_id_callback(unsigned long (*id_fn)(void)); struct evthread_condition_callbacks {
int 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);
}; int evthread_set_condition_callbacks(
const struct evthread_condition_callbacks *);

The evthread_lock_callbacks structure describes your locking callbacks and their abilities. For the version described above, the lock_api_version field must be set to

EVTHREAD_LOCK_API_VERSION. The supported_locktypes field must be set to a bitmask of the EVTHREAD_LOCKTYPE_* constants to describe which lock types you can support.

(As of 2.0.4-alpha, EVTHREAD_LOCK_RECURSIVE

is mandatory and EVTHREAD_LOCK_READWRITE is unused.) The alloc function must return a new lock of the specified type. The free function must release all resources held by a lock of the

specified type. The lock function must try to acquire the lock in the specified mode, returning 0 on success and nonzero on failure. The unlock function must try to unlock the lock, returning 0 on success and nonzero on failure.

理解:

evthread_lock_callbacks 包括了锁的回调函数和他们的功能,lock_api_version 要被设置为EVTHREAD_LOCK_API_VERSION,

supported_locktypes 应该设置为自己需要的EVTHREAD_LOCKTYPE_开头的几个类型的bitmask按位或

alloc 函数返回指定类型的锁,free 函数释放指定类型的锁的所有资源,lock 函数试图获取制定模式的锁,成功返回0,失败返回非0.

unlock 解锁函数释放指定的锁,成功返回0,失败返回非0

Recognized lock types are:

0

A regular, not-necessarily recursive lock.

EVTHREAD_LOCKTYPE_RECURSIVE

A lock that does not block a thread already holding it from requiring it again. Other threads can acquire the lock once the thread holding it has unlocked it as many times

as it was initially locked.

EVTHREAD_LOCKTYPE_READWRITE

A lock that allows multiple threads to hold it at once for reading, but only one thread at a time to hold it for writing. A writer excludes all readers.

0表示常规锁,不可以被重复上锁

EVTHREAD_LOCKTYPE_RECURSIVE:这种锁当一个线程持有,该线程可以继续获取他而不被阻塞,其他线程需要等到该线程释放这个锁后可以获取到这个锁,

并且可以多次加锁。

EVTHREAD_LOCKTYPE_READWRITE:这种锁多线程可以在读的时候都获取到他,但是写操作时只允许一个线程持有。

Recognized lock modes are:

EVTHREAD_READ

For READWRITE locks only: acquire or release the lock for reading.

EVTHREAD_WRITE

For READWRITE locks only: acquire or release the lock for writing.

EVTHREAD_TRY

For locking only: acquire the lock only if the lock can be acquired immediately.

EVTHREAD_READ和EVTHREAD_WRITE都是针对READWRITE 锁的获取和释放。

EVTHREAD_TRY:这个模式只在能立即获得锁的时候获取锁,否则不等待。

The id_fn argument must be a function returning an unsigned long identifying what thread is calling the function. It must always return the same number for the same thread, and must not ever return the same number for two different threads if they are both executing at the same time.

id_fn函数返回一个unsigned long标识调用该函数的线程。不同线程的返回值不同,同一个线程的返回值相同。

The evthread_condition_callbacks structure describes callbacks related to condition variables. For the version described above, the lock_api_version field must be set to EVTHREAD_CONDITION_API_VERSION. The alloc_condition function must return a pointer to a new condition variable. It receives 0 as its argument. The free_condition function must release storage and resources held by a condition variable. The wait_condition function takes three arguments: a condition allocated by alloc_condition, a lock allocated by the evthread_lock_callbacks.alloc function you provided, and an optional timeout. The lock will be held whenever the function is called; the function must release the lock, and wait until the condition becomes signalled or until the (optional) timeout has elapsed. The wait_condition function should return -1 on an error, 0 if the condition is signalled, and 1 on a timeout. Before it returns, it should make sure it holds the lock again. Finally, the signal_condition function should cause one thread waiting on the condition to wake up (if its broadcast argument is false) and all threads currently waiting on the condition to wake up (if its broadcast argument is true). It will only be held while holding the lock associated with the condition.

evthread_condition_callbacks 描述了几个跟条件变量相关的回调函数。lock_api_version 应该被设置为EVTHREAD_CONDITION_API_VERSION,alloc_condition 喊回一个指向新的环境变量的指针,

free_condition 释放条件变量的资源,wait_condition 带有三个参数,分别是alloc_condition开辟的条件变量,evthread_lock_callbacks开辟的锁,以及一个可选的超时值,在调用这个函数时lock要提前加锁,

之后,函数内部必须释放锁,等待条件被唤醒或者超时,wait_condition 在错误时返回-1,超时返回1,被激活返回0.在该函数内部返回之前,他要自己上锁。signal_condition 激活单个线程,broadcast 参数设为true时

所有等待该条件的线程被激活。只有持有和条件相关的锁的时候线程才会被挂起。

libevent中开辟锁和释放等等的回调函数以及条件变量的相关函数实现比较简单,就不展开了,可以查看evthread_pthread.c文件。

下面看下系统是如何调用

evthread_set_condition_callbacks()和evthread_set_lock_callbacks()分别将条件回调的结构体对象和锁相关功能的结构体对象

赋值给全局变量

_evthread_cond_fns和_evthread_lock_fns,

libevent封装了几个通过_evthread_cond_fns和 _evthread_lock_fns 调用锁和条件变量的接口,

都在evthread-internal.h文件里。

EVTHREAD_ALLOC_LOCK(lockvar, locktype);

EVTHREAD_FREE_LOCK(lockvar, locktype);

EVLOCK_LOCK(lockvar,mode);

EVLOCK_UNLOCK(lockvar,mode);

EVTHREAD_ALLOC_COND(condvar);

EVTHREAD_FREE_COND(cond);

EVTHREAD_COND_SIGNAL(cond);

EVTHREAD_COND_WAIT(cond, lock);

等等,就不展开了,读者自己阅读。

我的公众号

libevent文档学习(一)多线程接口和使用的更多相关文章

  1. Spring文档学习

    Spring文档学习 参考Spring Framework Documentation学习 1. IoC 容器 1.1 容器实例化 <beans> <import resource= ...

  2. EasyUI文档学习心得

    概述 jQuery EasyUI 是一组基于jQuery 的UI 插件集合,它可以让开发者在几乎完全不需要CSS以及复杂的JS代码情况下完成美观且功能强大的Web界面. 本文主要说明一些如何利用Eas ...

  3. 这可能是最详细的 iOS 学习入门指南(含书目/文档/学习资料)

    1 零基础小白如何进行 iOS 系统学习 首先,学习目标要明确: 其次,有了目标,要培养兴趣,经常给自己一些正面的反馈,比如对自己的进步进行鼓励,在前期小步快走: 再次,学技术最重要的一点就是多动手. ...

  4. Cassandra1.2文档学习解读计划——为自己鼓劲

    最近想深入研究一下Cassandra,而Cassandra没有中文文档,仅有的一些参考书都是0.7/0.6版本的.因此有个计划,一边学习文档(地址:http://www.datastax.com/do ...

  5. 《MATLAB从入门到放弃》二维曲线和图形绘制基础(二):使用Help文档学习line、plot、plotyy、subplot、hold绘图函数

    目录: »  plot 最常用的二维曲线绘图函数 >  帮助文档 >  基本使用语法 >  线条的样式.符号和颜色调整 >  图形属性调整 >  使用图形句柄进行设置 » ...

  6. Spring Security 官网文档学习

    文章目录 通过`maven`向普通的`WEB`项目中引入`spring security` 配置 `spring security` `configure(HttpSecurity)` 方法 自定义U ...

  7. swagger2 接口文档,整个微服务接口文档

    1,因为整个微服务会有好多服务,比如会员服务,支付服务,订单服务,每个服务都集成了swagger 我们在访问的时候,不可能每个服务输入一个url 去访问,看起来很麻烦,所以我们需要在一个页面上集成整个 ...

  8. SpringBoot整合knife4j框架(可生成离线接口文档),并设置接口请求头token默认值

    功能和swagger类似 官网地址:https://doc.xiaominfo.com/knife4j/ 这个框架可以设置返回字段的描述 引入依赖 <dependency> <gro ...

  9. 通过程序校验xml文档学习笔记

    校验xml文档,可以通过程序来校验,利用一段js代码即可. 各行代码的含义已经写出,运行这个html文件,检验如下xml代码: 结果如下: 如果xml文档出现错误: 结果如下: 其中,obj.asyn ...

随机推荐

  1. 高可用Kubernetes集群-4. kubectl客户端工具

    六.部署kubectl客户端工具 1. 下载 [root@kubenode1 ~]# cd /usr/local/src/ [root@kubenode1 src]# wget https://sto ...

  2. [leetcode-884-Uncommon Words from Two Sentences]

    We are given two sentences A and B.  (A sentence is a string of space separated words.  Each word co ...

  3. USACO 1.2.3 Name That Number 命名那个数字(打开文件)

    Description 在威斯康辛州牛大农场经营者之中,都习惯于请会计部门用连续数字给母牛打上烙印.但是,母牛用手机时并没感到这个系统的便利,它们更喜欢用它们喜欢的名字来呼叫它们的同伴,而不是用像这个 ...

  4. LeetCode 289. Game of Life (C++)

    题目: According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a ce ...

  5. 王者荣耀交流协会 - 第6次Scrum会议

    Scrum master :刘耀泽 补充:由于上次的scrum会议博客没有按时交上去,因此在这里给出上次scrum会议的链接: http://www.cnblogs.com/rensijia/p/76 ...

  6. git中的重要指令

    git命令 任何操作都需要以 git 命令为开头 本地操作: git init 初始化一个本地仓库 新建为 master主分支 git status 查看当前分支状态 git add <文件名& ...

  7. 20172314 蓝墨云课堂实践ASL

    由于去跳啦啦操没有上课... 介绍 折半查找,又称作二分查找.这个查找的算法的特点,就是,要求数据要是有序的. 1 ,存储结构一定是顺序存储 2 ,关键字大小必须有序排列 然后,利用这组有序的数据之间 ...

  8. HDU 5651 xiaoxin juju needs help 逆元

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5651 bc:http://bestcoder.hdu.edu.cn/contests/con ...

  9. lintcode-464-整数排序 II

    464-整数排序 II 给一组整数,按照升序排序.使用归并排序,快速排序,堆排序或者任何其他 O(n log n) 的排序算法. 样例 给出 [3, 2, 1, 4, 5], 排序后的结果为 [1, ...

  10. 用C++实现简单随机二元四则运算

    让我们想看看二元四则运算都需要实现什么: (1) 定制题目数量 (2) 是否有乘除法 (3) 题目数值范围 (4) 加减有无负数 (5) 除法有无余数 (6) 是否支持分数(真分数.假分数…) (7) ...