让libevent支持多线程 (使用socketpair通知方式)
2011-03-23 13:24
253 查看
libevent的使用方式是最开始调用event_init初始化一个全局的event_base指针,以后使用其中的API添加新的事件均是对这个指针进行的操作.
试想如下一种典型的场景:主线程使用libevent处理网络IO事件,接收新连接以及接收完客户端的数据之后将该事件交给辅助线程进行处理,辅助线程处理完了,需要往客户端发送回应数据,则再通过libevent提供的API将这个事件添加到可读事件中.但是,由于libevent中这个event_base指针是全局的,如果多线程同时添加可能会造成多线程不安全问题,这个在libevent的代码注释里面作者也做了注解.
在这个地方有人给出了解决的方案:
已经有现成的解决方案:
http://monkeymail.org/archives/libevent-users/2006-October/000257.html
原作者给的地址好像已经失效了。iunknown在 spserver 中就是使用了他的代码,可以从这里获得
http://code.google.com/p/spserver/source/browse/trunk/spserver/event_msgqueue.h
(对应的C文件可以通过修改上面文件的后缀名所得).
简单的说一说这个event_msgqueue的原理及使用方式:
它的结构体为:
struct event_msgqueue {
int push_fd;
int pop_fd;
int unlock_between_callbacks;
struct event queue_ev;
sp_thread_mutex_t lock;
void (*callback)(void *, void *);
void *cbarg;
struct circqueue *queue;
};
其中的queue是保存事件的队列,callback是处理事件的回调函数, lock是线程锁.
首先,它创建了一对socketpair(也就是结构体中的push_fd和pop_fd),将其中的一个通过libevent的event_add接口添加到关注的事件中,它的事件类型的是READ|PERSIST, 也就是说可读同时永不删除,而这个事件的回调函数是msgqueue_pop,这个函数的功能是将当前queue中的数据一一取出并且调用callback函数进行回调处理.
其次,外部的多线程需要往libevent添加事件时使用这个文件提供的msgqueue_push函数进行添加,此时, 往socketpair中发送一个字节的数据, 这么做的目的是为了让第一步已经添加的socketpair得到响应,此时, 由第一步,必然会触发之前注册的回调函数msgqueue_pop,将这个队列中的事件取出来进行处理.
这里使用socketpair起到了一个通知的作用,当队列中有数据时,通过向socketpair发送数据以调用msgqueue_pop,将数据取出来进行处理.
可见,这个event_msgqueue起了一个中间层的作用,辅助线程要往libevent添加事件就通过这个队列,当队列中有数据时再触发libevent的事件处理机制进行处理.设计的非常巧妙.
感谢iunknown兄的指点:)
试想如下一种典型的场景:主线程使用libevent处理网络IO事件,接收新连接以及接收完客户端的数据之后将该事件交给辅助线程进行处理,辅助线程处理完了,需要往客户端发送回应数据,则再通过libevent提供的API将这个事件添加到可读事件中.但是,由于libevent中这个event_base指针是全局的,如果多线程同时添加可能会造成多线程不安全问题,这个在libevent的代码注释里面作者也做了注解.
在这个地方有人给出了解决的方案:
已经有现成的解决方案:
http://monkeymail.org/archives/libevent-users/2006-October/000257.html
原作者给的地址好像已经失效了。iunknown在 spserver 中就是使用了他的代码,可以从这里获得
http://code.google.com/p/spserver/source/browse/trunk/spserver/event_msgqueue.h
(对应的C文件可以通过修改上面文件的后缀名所得).
简单的说一说这个event_msgqueue的原理及使用方式:
它的结构体为:
struct event_msgqueue {
int push_fd;
int pop_fd;
int unlock_between_callbacks;
struct event queue_ev;
sp_thread_mutex_t lock;
void (*callback)(void *, void *);
void *cbarg;
struct circqueue *queue;
};
其中的queue是保存事件的队列,callback是处理事件的回调函数, lock是线程锁.
首先,它创建了一对socketpair(也就是结构体中的push_fd和pop_fd),将其中的一个通过libevent的event_add接口添加到关注的事件中,它的事件类型的是READ|PERSIST, 也就是说可读同时永不删除,而这个事件的回调函数是msgqueue_pop,这个函数的功能是将当前queue中的数据一一取出并且调用callback函数进行回调处理.
其次,外部的多线程需要往libevent添加事件时使用这个文件提供的msgqueue_push函数进行添加,此时, 往socketpair中发送一个字节的数据, 这么做的目的是为了让第一步已经添加的socketpair得到响应,此时, 由第一步,必然会触发之前注册的回调函数msgqueue_pop,将这个队列中的事件取出来进行处理.
这里使用socketpair起到了一个通知的作用,当队列中有数据时,通过向socketpair发送数据以调用msgqueue_pop,将数据取出来进行处理.
可见,这个event_msgqueue起了一个中间层的作用,辅助线程要往libevent添加事件就通过这个队列,当队列中有数据时再触发libevent的事件处理机制进行处理.设计的非常巧妙.
感谢iunknown兄的指点:)
相关文章推荐
- 使用libevent和多线程构建高性能服务器(客户端)
- Windows API实现的栈及使用(支持线程安全,以原子方式操作)
- 【.Net】C#实现多线程的方式:使用Parallel类
- 使用HttpWebRequest发送HTTP请求,同时支持GET/POST方式提交。
- 关于IOS二维码创建、扫描的使用方式(IOS,ZBar支持64位解决办法)
- Spring中事务管理支持哪几种方式以及每种方式的具体使用方法
- 【我的Java笔记】多线程_使用匿名内部类的方式实现多线程
- struts2使用action方式实现文件下载(支持中文文件名)
- 使用HttpWebRequest发送HTTP请求,同时支持GET/POST方式提交。
- 通过匿名内部类方式使用多线程
- Java多线程学习笔记1——线程的实现方式以及定时器的使用
- JAVA多线程实现的三种方式(继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程)
- c#使用多线程的几种方式示例详解
- Boost asio学习笔记之一—— 使用strand支持多线程调用service_io的方法
- 使用jdk1.5的多线程 lock condition 实现方式实现 生产者消费者问题
- 未启用当前数据库的 SQL Server Service Broker,因此查询通知不受支持。如果希望使用通知,请为此数据库启用 Service Broker
- memcached使用libevent 和 多线程模式
- 未启用当前数据库的 SQL Server Service Broker,因此查询通知不受支持。如果希望使用通知,请为此数据库启用 Service Broker。]
- libevent带负载均衡的多线程使用示例
- 使用js和css方式,让IE8,IE9支持部分css3,html5