微信聊天警方可监控吗被骗钱 微信聊天警方可监控吗会向警方提供对方真实信息吗?

libevent学习笔记【使用篇】——(三)运行event loop
一旦一些events在event_base注册之后(下一节会讨论如何创建和注册events),就可以使Libevent等待events,并且在events准备好时能够通知你。
  默认情况下,event_base_loop()会在event_base上一直运行,直到其上已经没有注册的events了。运行loop时,它会重复检查那些已经注册的events是否触发了(比如,一个读event的文件描述符变得可读,或者后一个超时event已经超时)。一旦触发,该函数会将这些触发的events标记为active,并且开始运行回调函数。
#define EVLOOP_ONCE
#define EVLOOP_NONBLOCK
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
int event_base_loop(struct event_base *base, int flags);
可以通过设置一个或多个flag参数,来改变event_base_loop()函数的行为。如果设置了EVLOOP_ONCE,那么loop将会一直等待,直到一些events变为active,然后运行这些激活的events的回调函数,直到运行完所有激活的events为止,最后函数返回。如果设置了EVLOOP_NONBLOCK标志,则该函数不会等待events变为触发,它仅仅检查是否有事件准备好了,然后运行他们的回调函数,最后函数返回。
  event_base_loop函数返回0表示正常退出,返回-1表示后端方法发生了错误。返回1表示已经没有pending或active状态的events了。
  为了帮助理解,下面是event_base_loop算法的伪代码实现:
while(any events are registered with the loop,
or EVLOOP_NO_EXIT_ON_EMPTY was set) {
if (EVLOOP_NONBLOCK was set, or any eventsare already active)
If any registered events have triggered, mark them active.
Wait until at least one event has triggered, and mark it active.
for (p = 0; p & n_ ++p) {
if (any event with priority of p isactive) {
Run all active events with priorityof p.
/* Do not run any events of aless important priority */
if (EVLOOP_ONCE was set or EVLOOP_NONBLOCKwas set)
方便起见,也可以使用下面的接口:
intevent_base_dispatch(struct event_base *base);
  该函数等价于无标志的event_base_loop()函数。因此,直到没有注册的events,或者调用了event_base_loopbreak()、 event_base_loopexit(),该函数才会返回。
如果希望在所有events移除之前,就停止event loop的运行,有两个略有不同的接口可以调用:
int event_base_loopexit(struct event_base *base,
const struct timeval *tv);
int event_base_loopbreak(struct event_base *base);
event_base_loopexit()函数,使得event_base在经过了给定的超时时间之后,停止运行loop。如果tv参数为NULL,则event_base会立即停止loop。如果event_base正在运行active events的回调函数,则只有在运行完所有的回调之后,才停止loop。
  event_base_loopbreak()函数,使event_base立即退出loop。它与event_base_loopexit(base,NULL)不同之处在于,如果event_base当前正在运行任何激活events的回调函数,则会在当前的回调函数返回之后,就立即退出。
  注意: 当event loop没有运行时,event_base_loopexit(base, NULL)和 event_base_loopbreak(base)的行为是不同的:loopexit使下一轮event loop在下一轮回调运行之后立即停止(就像设置了EVLOOP_ONCE一样),而loopbreak仅仅停止当前loop的运行,而且在event loop未运行时没有任何效果。
  上述两个方法在成功是返回0, 失败时返回-1,。
立即停止:
/*Here's a callback function that calls loopbreak */
void cb(int sock, short what, void *arg)
struct event_base *base =
event_base_loopbreak(base);
void main_loop(struct event_base *base, evutil_socket_t watchdog_fd)
struct event *watchdog_
/* Construct a new event to triggerwhenever there are any bytes to
read from a watchdog socket.
When that happens, we'll call the
cb function, which will make the loop exitimmediately without
running any other active events at all.
watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base);
event_add(watchdog_event, NULL);
event_base_dispatch(base);
运行event loop10秒钟,然后退出。
void run_base_with_ticks(struct event_base *base)
struct timeval ten_
ten_sec.tv_sec = 10;
ten_sec.tv_usec = 0;
/* Now we run the event_base for a series of10-second intervals, printing
&Tick& after each.
For a much better way to implement a10-second
timer, see the section below aboutpersistent timer events. */
while (1) {
/* This schedules an exit ten seconds fromnow. */
event_base_loopexit(base, &ten_sec);
event_base_dispatch(base);
puts(&Tick&);
有些时候需要知道event_base_dispatch()或event_base_loop()的调用是正常退出,还是因为调用了event_base_loopexit()或event_base_break()而退出。可以使用下面的函数判断是否调用了loopexit或break:
int event_base_got_exit(struct event_base *base);
int event_base_got_break(structevent_base *base)
上述函数,如果loop的停止是因为调用了event_base_loopexit()或event_base_break() ,则会返回True。否则,会返回False。他们的值会在下次启动eventloop时被重置。
  上述函数在中声明。
重新检查events
一般情况下,Libevent会检查events,然后从高优先级的激活events开始运行,然后再次检查events。有时,你可能希望在运行完当前运行的回调函数之后,告知Libevent重新检查events。与event_base_loopbreak()类似,这可以通过调用event_base_loopcontinue()实现。
int event_base_loopcontinue(struct event_base *);
  如果当前没有运行events的回调函数的话,则该函数没有任何效果。
检查内部时间缓存
有时候可能需要在event回调函数内部,得到当前时间的近似视图,而且不希望使用gettimeoufday(可能是因为OS将gettimeofday()作为调用实现,而你希望避免系统调用的开销)。
  在回调函数内部,可以在开始执行这一轮的回调时,得到Libevent的当前时间的视图:
event_base_gettimeofday_cached(struct
event_base *base,
timeval*tv_out);
如果event_base正在执行回调函数的话,那么event_base_gettimeofday_cached()函数会将tv_out参数设置为缓存的时间。否则,它会调用evutil_gettimeofday()得到当前实际的时间。该函数成功返回0,失败返回负数。
  注意,因为当Libevent在开始执行回调的时候时间值才会被缓存,所以这个值会有一点不精确。如果回调执行很长时间,这个值将非常不精确。
  为了使缓存能够立即刷新,可以调用:
int event_base_update_cache_time(struct event_base *base);
  该函数在成功时返回0,失败时返回-1。而且在event_base没有运行eventloop时无效。
转储event_base状态
void event_base_dump_events(struct event_base *base, FILE *f);
为了调试程序的方便,有时会需要得到所有关联到event_base的events的列表以及他们的状态。调用event_base_dump_events()可以讲该列表输出到文件f中。
  得到的列表格式是人可读的形式,将来版本 的Libevent可能会改变其格式。
event_base中的每个event运行同一个回调函数
typedef int (*event_base_foreach_event_cb)(const struct event_base *, const structevent *, void *);
int event_base_foreach_event(struct event_base *base,
event_base_foreach_event_cb fn,
void *arg);
调用函数event_base_foreach_event(),遍历运行与event_base关联的每一个active或pending的event。每一个event都会运行一次所提供的回调函数,运行顺序是未指定的。event_base_foreach_event()函数的第三个参数将会传递给回调函数的第三个参数。
  回调函数必须返回0,才能继续执行遍历。否则会停止遍历。回调函数最终的返回值,就是event_base_foreach_function函数的返回值。
  回调函数不可修改它接收到的events参数,也不能为event_base添加或删除events,或修改关联到event_base上的任何events。否则将会发生未定义的行为,甚至是崩溃。
  在调用event_base_foreach_event期间,event_base的锁会被锁住。这样就会阻止其他线程使用该event_base,因而需要保证提供的回调函数不会运行太长时间。
废弃的loop函数
前面已经讨论过,老版本的Libevent具有&当前&event_base这样的全局概念。本文讨论的某些event loop函数具有操作当前event_base的变体函数。除了没有base参数外,这些函数跟当前新版本函数的行为相同。
废弃的函数
event_base_dispatch()
event_dispatch()
event_base_loop()
event_loop()
event_base_loopexit()
event_loopexit()
event_base_loopbreak()
event_loopbreak()
注意,2.0版本之前的event_base是不支持锁的,所以这些老版本的函数并不是完全线程安全的:不允许在执行event loop的线程之外的其他线程中调用_loopbreak()或者_loopexit()函数。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'课程名称读取中
支付宝支付
由百度云提供技术支持
&学院APP&&
扫描微信二维码精彩活动、课程更新抢先知
下载客户端,离线视频任您学
第一章:源码分析教程5部曲之3——libevent源码分
1.&源码分析教程5部曲之3—libevent源码概览
加入购物车
【课程类型】实战教学
【难度级别】高级
【适合人群】所有人
【课程介绍】 源码分析教程5部曲之3——libevent源码分析
【课程目标】 源码分析教程5部曲之3——libevent源码分析
【课程计划】 源码分析教程5部曲之3——libevent源码分析
第一章:源码分析教程5部曲之3——libevent源码分
[暂未上传]
全部评价(0)
8课程59321学员
参考知识库
为您推荐课程
讲师:杨振平 16课时
讲师:杨振平 2课时
讲师:杨振平 2课时
讲师:杨振平 2课时本文地址:
 Evbuffers: 缓冲化的I/O实用工具 
头文件:&event2/buffer.h&
Evbuffer基本操作
struct evbuffer *evbuffer_new (void);
void evbuffer_free (struct evbuffer *buf);
创建/销毁evbuffer
int evbuffer_enable_locking (struct evbuffer *buf, void *lock);
void evbuffer_lock (struct evbuffer *buf);
void evbuffer_unlock (struct evbuffer *buf);
第一个函数,参数locking传入的参数是一个锁。可以传入NULL,让evbffer自动创建一个锁。
size_t evbuffer_get_length (const struct evbuffer *buf);
size_t evbuffer_get_continous_space (const struct evbuffer *buf);
第一个函数,获取当前evbuffer的总数据长度。第二个函数,由于数据在evbuffer的内存中并不是连续保存的,这里返回第一个chunk的大小。
操作evbuffer中的帧
int evbuffer_add (struct evbuffer *buf, const void *data, size_t data_len);
int evbuffer_add_printf (struct evbuffer *buf, const char *fmt);
int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);
直接往evbuffer的末尾添加数据
int evbuffer_expand (struct evbuffer *buf, size_t data_len);
扩展ev_buffer的预申请内存
int evbuffer_add_buffer (struct evbuffer *dst, struct evbuffer *src);
int evbuffer_rename_buffer (struct evubffer *src, struct evbuffer *dst, size_t data_len);
两个函数都是“move”操作,也就是说会删除src的指定内容。
int evbuffer_prepend (struct evbuffer *buf, const void *data, size_t size);
int evbuffer_prepend_buffer (struct evbuffer *dst, struct evbuffer *src);
这两个函数是往evbuffer的头部插入数据
unsigned char *evbuffer_pullup (struct evbuffer *buf, ev_ssize_t size);
将指定长度的数据存入到evbuffer的第一个chunk中。如果size为-1,则表示全部。
int evbuffer_drain (struct evbuffer *buf, size_t len);
int evbuffer_remove (struct evbuffer *buf, void *data, size_t data_len);
从evbuffer的头部放走指定长度的数据,第二个函数可以顺带读出来。
基于字符串行的输入
很多文件都是一行一行存储的(比如文本),一下函数可以用来一行一行地读取输入(ASCII)。读取之前要指定行尾的格式。
enum evbuffer_eol_style {
EVBUFFER_EOL_ANY,
// 任意数量的\r和\n
EVBUFFER_EOL_CRLF,
// \r或者\r\n
EVBUFFER_EOL_CRLF_STRICT,
EVBUFFER_EOL_LF,
EVBUFFER_EOL_NUL
char *evbuffer_readln (struct evbuffer *buffer,
size_t *n_read_out,
enum evbuffer_eol_style eol_style);
在evbuffer里面搜索
Evbuffer使用一个结构体来配置搜索功能,其中pos表示position,如下:
struct evbuffer_ptr {
struct {/* internal fields */} _
struct evbuffer_ptr evbuffer_search (struct evbuffer *buffer,
const char *what,
size_t len,
const struct evbuffer_ptr *start);
struct evbuffer_ptr evbuffer_search_range (struct evbuffer *buffer,
const char *what,
size_t len,
const struct evbuffer_ptr *start,
const struct evbuffer_ptr *end);
struct evbuffer_ptr evbuffer_search_eol (struct evbuffer_ptr *buffer,
struct evbuffer_ptr *start,
size_t *eol_len_out,
enum evbuffer_eol_style eol_style);
第一个参数是搜索在evbuffer中与“what”参数相同的数据并且返回。如果参数start不为空,则会从start中所指定的位置开始搜索。  第二个函数的不同是指定了一个搜索范围;第三个函数类似于evbuffer_readln,但是不复制,只是返回结果而已。
enum evbuffer_ptr_how {
EVBUFFER_PTR_SET,
EVBUFFER_PTR_ADD,
int evbuffer_ptr_set (struct evbuffer *buffer,
struct evbuffer_ptr *pos,
size_t position,
enum evbuffer_ptr_how how);
修改evbuffer中的evbuffer_ptr。
检查数据但是不复制出来
sruct aevbuffer_iovec {
void *iov_
size_t iov_
int evbuffer_peak (struct evbuffer *buffer,
ev_size_t len,
struct evbuffer_ptr *start_atm
struct evbuffer_iovec *vec_out,
int n_vec);
这个函数给予一个struct evbuffer_iovec数组,并且用n_vec制定长度,从evbuffer中得到的具体数据块的信息,这样就可以直接读取了。如果start_at非空,则直接从制定的位置读起。
直接向evbuffer添加数据
int evbuffer_reserve_space (struct evbuffer *buf,
ev_size_t size,
struct evbuffer_iovec *vec,
int n_vecs);
int evbuffer_commit_space (struct evbuffer *buf,
struct evbuffer_iovec *vec,
int n_vecs);
这个函数与peak类似,不同的是使用这个组合,可以直接修改evbuffer里面的值。如果是多线程的情况下,注意要在reserve之前加锁、commit之后解锁。
使用evbuffer对网络I/O进行读写
int evbuffer_write (struct evbuffer *buffer, evutil_socket_t fd);
int evbuffer_write_almost (struct evbuffer *buffer, evutil_socket_t fd, ev_ssize_t howmuch);
int evubffer_read (struct evbuffer *buffer, evutil_socket_t fd, ev_ssize_t howmuch);
evbuffer_write等同于evbuffer_write_almost中的howmuch参数指定为-1。
Evbuffer的回调函数
struct evbuffer_cb_info {
size_t orig_
typedef void (*evbuffer_cb_func)(struct evbuffer *buffer,
const struct evbuffer_cb_info *info,
void *arg);
struct evbuffer_cb_
struct evbuffer_cb_func *evbuffer_add_cb (struct evbuffer *buffer,
evbuffer_cb_func cb,
void *cbarg);
当evbuffer有操作时,会调用callback,返回entry,则可以用来在后续的函数中引用这个callback。
int evbuffer_remove_cb_entry (struct evbuffer *buffer, struct evbuffer_cb_func *ent);
int evbuffer_remove_cb (struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg);
这两个函数用于删除callback
int evbuffer_defer_callbacks (struct evbuffer *buffer, struct event_base *base);
Evbuffer的callback也可以放在event loop里面,这两个函数就是将callback进行defer的函数
为基于evbuffer的I/O减少数据复制
基于evbuffer经常会有数据复制,但是很多大负荷的服务器要尽量减少这些操作,此时就需要以下函数:
typedef void (*evbuffer_ref_cleanup_cb) (const void *data, size_t datalen, void *extra);
int evbuffer_add_reference (struct evbuffer *outbuf,
const void *data,
size_t datalen,
evbufferref_cleanup_cb cleanupfn,
void *extra);
这个函数通过引用想evbuffer添加一段void *数据并且指定其长度。这段数据必须持续保持有效,直到evbuffer调用callback为止。
向evbuffer直接添加文件内容
(很少用,暂略)
evbuffer之间的复制
int evbuffer_add_buffer_reference (struct evbuffer *outbuf, struct evbuffer *inbuf);
暂时冻结evbuffer
int evbuffer_freeze (struct evbuffer *buf, int at_front);
int evbuffer_unfreeze (struct evbuffer *buf, int at_front);
你可能感兴趣的文章
6 收藏,918
1 收藏,639
69 收藏,5k
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
我要该,理由是:
扫扫下载 App
SegmentFault
一起探索更多未知libevent学习笔记【使用篇】(四)让events正常工作_其它编程-织梦者
当前位置:&>&&>& > libevent学习笔记【使用篇】(四)让events正常工作
libevent学习笔记【使用篇】(四)让events正常工作
一构建event对象
二事件持久性
EV_PERSIST
三 创建一个可以将自身作为回调函数参数的的event
四纯超时events
五 构造信号事件
六不在堆中分配event
七将events置为挂起或者非挂起
八事件的优先级
九检查event状态
十找到当前正在运行的event
十一配置一次性的events
十二手动激活event
十三优化一般性超时
十四从已清除的内存识别事件
十五过时的event处理函数
翻译自:http://www.wangafu.net/~nickm/libevent-book/Ref4_event.html
文章出处 http://blog.csdn.net/windeal3203/article/details/
Libevents的基本操作单元是event,每一个event代表了一些条件的集合,这些条件包括:
文件描述符已经准备好读或写
文件描述符正在变为就绪,准备好读或写(仅限于边沿触发)
用户触发事件
  events都有类似的生命周期。一旦调用Libevent函数创建好event,并将其关联到一个event_base之后,他就是“已初始化”状态(initialized)。这种状态下,可以进行add操作,将其状态变为base中的“挂起”状态(pending),处于“挂起”状态的event,如果触发事件的条件发生了(比如,文件描述符的状态发生变化,或者超时了),那么event的状态变为“激活”状态(active),然后它的回调函数(用户提供)开始运行。如果该event配置了“持久”属性(persistent),那么它的状态依然保持为“挂起”,否则,在回调函数运行时,它的状态就不再是“挂起”(“非挂起”状态)。可以通过delete操作,将一个“挂起”状态的event变为“非挂起”状态(non-pending),或者通过add操作,将“非挂起”的event变为“挂起”状态。
一、构建event对象
  创建新的event,可以使用event_new接口:
#define EV_TIMEOUT
#define EV_READ
#define EV_WRITE
#define EV_SIGNAL
#define EV_PERSIST
#define EV_ET
typedef void
(*event_callback_fn)(evutil_socket_t,
struct event * event_new(struct
event_base *base,
evutil_socket_t
short what,
event_callback_fn
void* arg);
event_free(struct
event * event);
   event_new函数分配并且创建一个新的event对象,并与base进行关联。what参数是上面列出标志的集合,它们的具体意义见下方。如果fd是非负的整数,则它代表了我们需要观察可读或可写事件的文件。当event变为激活时,Libevent就会调用回调函数cb,将文件描述符参数fd,所有触发事件的标志位域,以及event_new的最后一个参数:arg传递给cb。
  如果发生了内部错误,或者参数非法,则event_new返回NULL。
  所有新的events都是“已初始化”和“非挂起”状态,可以调用event_add函数将这样的event变为“挂起”状态。
  调用event_free可以销毁event。对“挂起”或“激活”状态的event调用event_free也是安全的:在销毁它之前,会将其变为“非挂起”以及“非激活”状态。
  上述函数在&event2/event.h&文件中定义。
event标志:
EV_TIMEOUT:
该标志表明,超时时间过后,该event变为“激活”状态。(注意:在构建event时,EV_TIMEOUT标志是被忽略的:当add event时可以设置超时时间,也可以不设置。当超时发生时,回调函数的what参数将会设置该标志。)
该标志表明,当文件描述符准备好读时,event将会变为“激活”
EV_WRITE:
该标志表明,当文件描述符准备好写时,event将会变为“激活”
EV_SIGNAL:
用来实现信号探测,参见下面的“构造信号事件”
EV_PERSIST:
标志该event具有“持久”属性,参见下面的“事件持久性”
指明如果event_base的底层方法支持边沿触发的话,那么该event应该是边沿触发的。这将会影响到EV_READ和EV_WRITE
  自Libevent2.0.1-alpha版本以来,同一时刻,针对同一个文件描述符,可以有任意数量的event在同样的条件上“挂起”。比如,当给定的fd变为可读时,可以使两个events都变为激活状态。但是他们的回调函数的调用顺序是未定义的。
  所有这些标志都在&event2/event.h&中定义。
#include &event2/event.h&
cb_func(evutil_socket_t
short what,
void * arg)
const char *data =
printf("Got an event on socket %d:%s%s%s%s [%s]",
(what&EV_TIMEOUT) ? " timeout" : "",
(what&EV_READ)
? " read" : "",
(what&EV_WRITE)
? " write" : "",
(what&EV_SIGNAL)
? " signal" : "",
main_loop(evutil_socket_t
evutil_socket_t fd2)
event *ev1, *ev2;
five_seconds = {5,0};
event_base * base = event_base_new();
/* The caller has already set up fd1,fd2 somehow, and make them
nonblocking. */
ev1 = event_new(base,
EV_TIMEOUT|EV_READ|EV_PERSIST,
(char*)"Reading event");
ev2 = event_new(base,
EV_WRITE|EV_PERSIST,
(char*)"Writing event");
event_add(ev1,
&five_seconds);
event_add(ev2,
event_base_dispatch(base);
二、事件持久性
EV_PERSIST
  默认情况下,当一个“挂起”的event变为“激活”时(要么是因为fd准备好读或写,要么是超时时间到),那么在它的回调函数执行之前,它就会变为“非挂起”状态。因此,如果希望再次使event变为“挂起”状态,可以在回调函数内部再次调用event_add函数。
  如果event设置了EV_PERSIST标志,那么event就是“持久”的。这意味着event在回调函数激活的时候,依然保持“挂起”状态。如果希望在回调函数中将event变为“非挂起”状态,则可以调用event_del函数。
  当event的回调函数运行时,“持久”event的超时时间就会被重置。因此,如果某个event标志为EV_READ|EV_PERSIST,并且将超时时间设置为5秒,则该event在下面的条件发生时,会变为“激活”:当该socket准备好读时; 距离上次event变为激活状态后,又过了5秒钟.
三 、创建一个可以将自身作为回调函数参数的的event
  经常可能会希望创建这样一个event,它本身就是是回调函数的参数之一。不能仅仅传递一个指向event的指针作为event_new的参数,因为彼时它还没有创建。此时,可以通过调用event_self_cbarg函数解决这样的问题。
void*event_self_cbarg();
  该函数返回一个“魔术”指针,使得event_new创建一个本身就能作为回调函数参数的event。
#include &event2/event.h&
static int
n_calls = 0;
cb_func(evutil_socket_t
short what,
void * arg)
event *me =
printf("cb_func
so far.\n",
++n_calls);
if (n_calls & 100)
event_del(me);
run(struct
event_base * base)
one_sec = { 1, 0 };
/* We're going to set up a repeating timerto get called 100 times. */
ev = event_new(base,
EV_PERSIST, cb_func,
event_self_cbarg());
event_add(ev,
&one_sec);
event_base_dispatch(base);
   该函数还可以与函数event_new,evtimer_new, evsignal_new, event_assign, evtimer_assign和evsignal_assign一起使用。然而对于非event来说,他不会作为回调函数的参数。
四、纯超时events
  方便起见,Libevent提供了一系列以evtimer_开头的宏,这些宏可以代替event_*函数,来分配和操作纯超时events。使用这些宏仅能提高代码的清晰度而已。
#define evtimer_new(base,
event_new((base), -1, 0, (callback), (arg))
#define evtimer_add(ev,
event_add((ev),(tv))
#define evtimer_del(ev)
event_del(ev)
#define evtimer_pending(ev,
event_pending((ev), EV_TIMEOUT, (tv_out))
五 、构造信号事件
  Libevent也可以监控POSIX类的信号。构建一个信号处理函数,可以使用下面的接口:
#define evsignal_new(base,
event_new(base,
EV_SIGNAL|EV_PERSIST,
  除了提供一个代表信号值的整数,而不是一个文件描述符之外。它的参数与event_new是一样的。
struct event * hup_
struct event_base
*base = event_base_new();
/*call sighup_function on a HUP signal */
hup_event= evsignal_new(base,
sighup_function,
  注意:信号回调函数是在信号发生之后,在eventloop中调用的。所以,它们可以调用那些,对于普通POSIX信号处理函数来说不是信号安全的函数。
  注意:不要在一个信号event上设置超时,不支持这样做。
  对于信号event,同样有一些方便的宏可以使用:
#define evsignal_add(ev,
event_add((ev), (tv))
#define evsignal_del(ev)
event_del(ev)
#define evsignal_pending(ev,
event_pending((ev), (what), (tv_out))
  警告:当前版本的Libevent,对于大多数的后端方法来说,同一时间,每个进程仅能有一个event_base可以用来监听信号。如果一次向两个event_base添加event,即使是不同的信号,也仅仅会只有一个event_base可以接收到信号。对于kqueue来说,不存在这样的限制。
六、不在堆中分配event
  出于性能或者其他原因的考虑,一些人喜欢将event作为一个大的结构体的一部分进行分配。对于这样的event,它节省了:
内存分配器在堆上分配小对象的开销;
event指针的解引用的时间开销;
如果event没有在缓存中,缓存不命中的时间开销。
  这种方法的风险在于,与其他版本的Libevent之间不满足二进制兼容性,他们可能具有不同的event大小。
  这些开销都非常小,对于大多数应用来说是无关紧要的。除非确定知道,应用程序因为使用堆分配的event而存在严重的性能损失,否则应该坚持实用event_new。 如果后续版本的Libevent使用比当前Libevent更大的event结构,那么使用event_assign有可能会导致难以诊断的错误。
event_assign(struct
event * event, struct
event_base * base,
evutil_socket_t fd,
void(*callback)(evutil_socket_t,
void * arg);
  event_assign的参数与event_new相同,除了event参数,该参数指针必须指向一个未初始化的event。该函数成功时返回0,失败时返回-1.
#include &event2/event.h&
/*Watch out! Including event_struct.h means that your code willnot
* be binary-compatible with future versions ofLibevent. */
#include &event2/event_struct.h&
#include &stdlib.h&
struct event_pair {
evutil_socket_
struct event
struct event
readcb(evutil_socket_t,
writecb(evutil_socket_t,
struct event_pair * event_pair_new(struct
event_base * base,
evutil_socket_t
event_pair
*p = malloc(sizeof(struct
event_pair));
if (!p) return NULL;
event_assign(&p-&read_event,
fd, EV_READ|EV_PERSIST,
event_assign(&p-&write_event,
EV_WRITE|EV_PERSIST,writecb, p);
  同样可以使用event_assign来初始化栈或者静态存储区中的events。
警告:对于已经在event_base中处于“挂起”状态的event,永远不要调用event_assign。这样做会导致极为难以诊断的错误。如果event已经初始化,并且处于“挂起”状态,那么在调用event_assign之前应该先调用event_del。*
  对于使用event_assign分配的纯超时event或者信号event,同样有方便的宏可以使用:
#define evtimer_assign(event,
callback, arg) \
event_assign(event, base,
#define evsignal_assign(event,
signum, callback,
event_assign(event, base,
EV_SIGNAL|EV_PERSIST,
  如果需要在与未来版本的Libevent保持二进制兼容性的同时,使用event_assign,可以调用Libevent中的函数,得到运行时的event结构大小:
size_t event_get_struct_event_size(void);
  该函数返回需要为event结构预留的字节数。再次提醒,只有在确定堆分配导致很明显的性能问题时,才应该使用该函数,因为它使你的代码难读又难写。
  注意,将来版本的event_get_struct_event_size()的返回值可能比sizeof(structevent)小,这意味着event结构的末尾的额外字节仅仅是保留用于未来版本的Libevent的填充字节。
  下面是一个使用event_get_struct_size的例子:
#include &event2/event.h&
#include &stdlib.h&
/*When we allocate an event_pair in memory, we'll actually allocate
* more space at the end of the structure.
We define some macros
* to make accessing those events lesserror-prone. */
struct event_pair {
evutil_socket_
/*Macro: yield the struct event 'offset' bytes from the start of 'p' */
#define EVENT_AT_OFFSET(p,
event*) ( ((char*)(p)) + (offset) ))
/*Macro: yield the read event of an event_pair */
#define READEV_PTR(pair) \
EVENT_AT_OFFSET((pair),
sizeof(struct event_pair))
/*Macro: yield the write event of an event_pair */
#define WRITEEV_PTR(pair) \
EVENT_AT_OFFSET((pair), \
sizeof(struct
event_pair)+event_get_struct_event_size())
/*Macro: yield the actual size to allocate for an event_pair */
#defineEVENT_PAIR_SIZE() \
(sizeof(struct
event_pair)+2*event_get_struct_event_size())
voidreadcb(evutil_socket_t, short, void *);
voidwritecb(evutil_socket_t, short, void *);
struct event_pair *event_pair_new(struct
event_base *base, evutil_socket_t
event_pair *p = malloc(EVENT_PAIR_SIZE());
if (!p) return NULL;
event_assign(READEV_PTR(p), base, fd,EV_READ|EV_PERSIST, readcb, p);
event_assign(WRITEEV_PTR(p), base, fd,EV_WRITE|EV_PERSIST, writecb, p);
  event_assign函数定义在文件&event2/event.h&中。event结构体定义在&event2/event_struct.h&文件中。
七、将events置为“挂起”或者“非挂起”
  刚创建的一个event,实际上不能做任何事,直到通过调用event_add进行adding操作,将其置为“挂起”状态。
event_add(struct
event *ev,
struct timeval
  在“非挂起”状态的events上执行event_add操作,则会使得该event在配置的event_base上变为“挂起”状态。该函数返回0表示成功,返回-1表示失败。如果tv为NULL,则该event没有超时时间。否则,tv以秒和毫妙表示超时时间。
  如果在已经是“挂起”状态的event进行event_add操作,则会保持其“挂起”状态,并且会重置其超时时间。如果event已经是“挂起”状态,而且以NULL为超时时间对其进行re-add操作,则event_add没有任何作用。
  注意:不要设置tv为希望超时事件执行的时间,比如如果置tv-&tv_sec=time(NULL)+10,并且当前时间为,则超时时间为40年之后,而不是10秒之后。
event_del(struct event *ev);
  在已经初始化状态的event上调用event_del,则会将其状态变为“非挂起”以及“非激活”状态。如果event的当前状态不是“挂起”或“激活”状态,则该函数没有任何作用。该函数返回0表示成功,返回-1表示失败。
  注意,如果在event刚变为“激活”状态,但是它的回调函数还没有执行时,调用event_del函数,则该操作使得它的回调函数不会执行。
event_remove_timer(struct
event *ev);
  最后,可以在不删除event上的IO事件或信号事件的情况下,删除一个“挂起”状态的event上的超时事件。如果该event没有超时事件,则event_remove_timer没有作用。如果event没有IO事件或信号事件,只有超时事件的话,则event_remove_timer等同于event_del。该函数返回0表示成功,-1表示失败。
  这些函数都是在文件&event2/event.h&中定义的。
八、事件的优先级
  当多个事件在同一时间触发时,Libevent对于他们回调函数的调用顺序是没有定义的。可以通过优先级,定义某些“更重要”的events。
  每一个event_base都有一个或多个优先级的值。在event初始化之后,添加到event_base之前,可以设置该event的优先级。
event_priority_set(struct
event *event,
priority);
  event的优先级数必须是位于0到event_base优先级-1这个区间内。该函数返回0表示成功,返回-1表示失败。
  当具有多种优先级的多个events同时激活的时候,低优先级的events不会运行。Libevent会只运行高优先级的events,然后重新检查events。只有当没有高优先级的events激活时,才会运行低优先级的events。
#include &event2/event.h&
read_cb(evutil_socket_t,
write_cb(evutil_socket_t,
voidmain_loop(evutil_socket_t
*important,
event_base
base = event_base_new();
event_base_priority_init(base, 2);
/* Now base has priority 0, and priority 1 */
important = event_new(base,
EV_WRITE|EV_PERSIST,
unimportant = event_new(base,
EV_READ|EV_PERSIST, read_cb,
event_priority_set(important, 0);
event_priority_set(unimportant, 1);
/*Now, whenever the fd is ready for writing, the write callback will
happen before the read callback.
The read callback won't happen at
all until the write callback is no longeractive.*/
  如果没有设置一个event的优先级,则它的默认优先级是“event_base队列长度”除以2。该函数在文件&event2/event.h&中声明。
九、检查event状态
  有时可能希望知道event是否已经添加了(处于“挂起”状态),或者检查他关联到哪个event_base等。
event_pending(const struct
event *ev,
struct timeval
#define event_get_signal(ev) /* ... */
evutil_socket_t event_get_fd(const
event *ev);
struct event_base *event_get_base(const
struct event
short event_get_events(const
event_callback_fn event_get_callback(const
struct event *ev);
void*event_get_callback_arg(const
event_get_priority(const struct
event *ev);
event_get_assignment(const struct event*event,
event_base
**base_out,
evutil_socket_t
*events_out,
event_callback_fn
*callback_out,
**arg_out);
  event_pending函数检查给定的event是否处于“挂起”或“激活”状态。如果确实如此,并且在what参数中设置了任何EV_READ, EV_WRITE, EV_SIGNAL或EV_TIMEOUT标志的话,则该函数返回所有该event当前正在“挂起”或“激活”的标志。
  如果提供了tv_out参数,且在what参数中设置了EV_TIMEOUT参数,并且当前event确实在超时事件上“挂起”或者“激活”,则tv_out就会设置为event的超时时间。
  event_get_fd和event_get_signal函数返回event上配置的文件描述符或者信号值。event_get_base()返回其配置的event_base。event_get_events()返回event上配置的事件标志(EV_READ,EV_WRITE等)。event_get_callback函数和event_get_callback_arg函数返回event的回调函数和参数指针。event_get_priority函数返回event的当前优先级。
  event_get_assignment函数在提供的参数指针中返回event的所有成分,如果参数指针为NULL,则该成分被忽略。
#include &event2/event.h&
#include &stdio.h&
/*Change the callback and callback_arg of 'ev', which must not be pending. */
replace_callback(struct
event *ev,
event_callback_fn
new_callback,
void* new_callback_arg)
event_base
evutil_socket_
pending = event_pending(ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL);
if (pending) {
/*We want to catch this here so that we do notre-assign a
* pending event.
That would be very very bad.*/
fprintf(stderr, "Error! replace_callbackcalled on a pending event!\n");
return -1;
event_get_assignment(ev,
&base, &fd,
NULL /* ignore oldcallback */ ,
NULL /* ignore oldcallback argument */);
event_assign(ev,
events,new_callback,
new_callback_arg);
这些函数在文件&event2/event.h&中定义。
十、找到当前正在运行的event
  在调试程序时,可以得到当前正在运行的event的指针。
struct event * event_base_get_running_event(struct event_base * base);
  注意,只有在base的loop中调用该函数,该函数才有意义。在其他线程调用时不支持的,而且会导致未定义的行为。
  该函数在&event2/event.h&中声明。
十一、配置一次性的events
  如果不需要对一个event进行多次添加,或者对一个非持久的event,在add之后就会delete,则可以使用event_base_once函数。
int event_base_once(struct event_base *,
evutil_socket_t,
void (*) (evutil_socket_t,
const struct timeval *);
  该函数的参数与event_new一样,不同的是它不支持EV_SIGNAL或EV_PERSIST标志。得到的内部event会以默认的优先级添加到event_base中并运行。当它的回调函数执行完成之后,Libevent将会释放该内部event。该函数成功时返回0,失败是返回-1.
  通过event_base_once插入的event不能被删除或者手动激活。如果希望可以取消一个event,则需要通过常规的event_new或event_assign接口创建event。
  注意,直到Libevent2.0之前,如果event一直没有触发,则它的内存永远不会被释放。从Libevent2.1.2-alpha版本开始,当event_base释放时,即使events还没有被激活,它们的内存也会被释放。但是依然要注意:如果它们的回调函数的参数具有关联的内存,那么除非程序中进行释放,否则这些内存永远不会被释放。
十二、手动激活event
  某些极少的情况下,你可能希望在条件未被触发的情况下就激活event;
event_active(struct
event *ev, int
what, short
  该接口使得event变为“激活”状态,激活标志在what中传入(EV_READ, EV_WRITE和EV_TIMEOUT的组合)。该event之前的状态不一定非得要是“挂起”状态,而且将其激活不会使其状态变为“挂起”状态。
  警告:在同一个event上递归调用event_active可能会导致资源耗尽。下面的例子就是不正确的示范:
structevent *
static void cb(int
short which,
void *arg) {
/* Whoops: Calling event_active on thesame event unconditionally
from within its callback means that no other eventsmight not get
event_active(ev,
char**argv) {
event_base *base = event_base_new();
ev = event_new(base,
EV_PERSIST| EV_READ,
cb, NULL);
event_add(ev, NULL);
event_active(ev, EV_WRITE, 0);
event_base_loop(base, 0);
上面的例子描述了这样的情形:event loop仅被执行一次,而cb会被无限的递归调用中。
Example:Alternative solution to the above problem using timers
struct event *
static void
sock,short
void *arg) {
if (!evtimer_pending(ev, NULL)) {
event_del(ev);
evtimer_add(ev, &tv);
char**argv) {
event_base
*base = event_base_new();
tv.tv_sec = 0;
tv.tv_usec = 0;
ev = evtimer_new(base,
evtimer_add(ev, &tv);
event_base_loop(base, 0);
Example:Alternative solution to the above problem usingevent_config_set_max_dispatch_interval()
structevent *
static void
sock, short
void*arg) {
event_active(ev,
intmain(int argc,
char **argv) {
event_config
*cfg = event_config_new();
/* Run at most 16 callbacks beforechecking for other events. */
event_config_set_max_dispatch_interval(cfg,
event_base *base =event_base_new_with_config(cfg);
ev = event_new(base,
EV_PERSIST| EV_READ,
event_add(ev, NULL);
event_active(ev, EV_WRITE, 0);
event_base_loop(base, 0);
该方法在 &event2/event.h&中定义。
十三、优化一般性超时
  当前版本的Libevent使用二叉堆算法来对”挂起”状态的event超时时间值进行跟踪。对于有序的添加和删除event超时时间的操作,二叉堆算法可以提供O(lg n)的性能。这对于添加随机分布的超时时间来说,性能是最优的,但是如果是大量相同时间的events来说就不是了。
  比如,假设有一万个事件,每一个event的超时时间都是在他们被添加之后的5秒钟。在这种情况下,使用双向队列实现的话,可以达到O(1)的性能。
  正常情况下,一般不希望使用队列管理所有的超时时间值,因为队列仅对于恒定的超时时间来说是快速的。如果一些超时时间或多或少的随机分布的话,那添加这些超时时间到队列将会花费O(n)的时间,这样的性能要比二叉堆差多了。
  Libevent解决这种问题的方法是将一些超时时间值放置在队列中,其他的则放入二叉堆中。可以向Libevent请求一个“公用超时时间”的时间值,然后使用该时间值进行事件的添加。如果存在大量的event,它们的超时时间都是这种单一公用超时时间的情况,那么使用这种优化的方法可以明显提高超时事件的性能。
const struct
timeval * event_base_init_common_timeout(
struct event_base *base,
timeval* duration);
  该方法的参数有event_base,以及一个用来初始化的公用超时时间值。该函数返回一个指向特殊timeval结构体的指针,可以使用该指针表明将event添加到O(1)的队列中,而不是O(lg n)的堆中。这个特殊的timeval结构可以在代码中自由的复制和分配。该timeval只能工作在特定的event_base上(参数)。不要依赖于该timeval的实际值:Libevent仅使用它们来指明使用哪个队列。
#include &event2/event.h&
#include &string.h&
/*We're going to create a verylarge number of events on a given base,
* nearly all of which have a ten-secondtimeout. If initialize_timeout
* is called, we'll tell Libevent to add theten-second ones to an O(1)
* queue. */
struct timeval
ten_seconds = { 10, 0 };
initialize_timeout(struct
event_base *base)
tv_in = { 10, 0 };
timeval*tv_
tv_out =event_base_init_common_timeout(base, &tv_in);
memcpy(&ten_seconds,tv_out, sizeof(struct timeval));
my_event_add(struct
event *ev, const
timeval*tv)
/* Note that ev must have the sameevent_base that we passed to
initialize_timeout */
if (tv && tv-&tv_sec == 10 && tv-&tv_usec == 0)
return event_add(ev, &ten_seconds);
return event_add(ev, tv);
  类似于其他所有的优化函数,除非确定对你有用,否则应该避免使用这种公用超时时间功能。
十四、从已清除的内存识别事件
  Libevent提供了这样的函数,可以从已经清0的内存中(比如以calloc分配,或者通过memset或bzero清除)识别出已初始化的event。
event_initialized(const
event*ev);
#define evsignal_initialized(ev)
event_initialized(ev)
#define evtimer_initialized(ev)
event_initialized(ev)
  警告:这些函数不能在一块未初始化的内存中识别出已经初始化了的event。除非你能确定该内存要么被清0,要么被初始化为event,否则不要使用这些函数。
  一般情况下,除非你的应用程序有着极为特殊的需求,否则不要轻易使用这些函数。通过event_new返回的events永远已经初始化过的。
#include &event2/event.h&
#include &stdlib.h&
struct reader {
evutil_socket_
#defineREADER_ACTUAL_SIZE()
(sizeof(struct
reader) + event_get_struct_event_size())
#defineREADER_EVENT_PTR(r)
event *) (((char*)(r))+sizeof(struct
struct reader * allocate_reader(evutil_socket_t fd)
reader *r = calloc(1, READER_ACTUAL_SIZE());
readcb(evutil_socket_t,
add_reader(struct
reader *r, struct
event_base *b)
*ev= READER_EVENT_PTR(r);
if (!event_initialized(ev))
event_assign(ev,
event_add(ev, NULL);
十五、过时的event处理函数
  在Libevent2.0之前的版本中,没有event_assign或者event_new函数,而只有event_set函数,该函数返回的event与“当前”base相关联。如果有多个event_base,则还需要调用event_base_set函数指明event与哪个base相关联。
event_set(struct
*event, evutil_socket_t
short what,
void(*callback)(evutil_socket_t,
void *arg);
event_base_set(struct
event_base * base,
event *event);
  event_set函数类似于event_assign,除了它使用“当前”base的概念。event_base_set函数改变event所关联的base。
  如果是处理超时或者信号events,event_set也有一些便于使用的变种:evtimer_set类似于evtimer_assign,而evsignal_set类似于evsignal_assign。
  Libevent2.0之前的版本中,使用以signal_为前缀的函数作为处理基于信号的event_set的变种。而不是evsignal_(也就是说是:signal_set, signal_add, signal_del, signal_pending和signal_intialized)。Libevent古老版本(0.6之前),使用timeout_,而不是evtimer_前缀。因此,如果你需要处理很老的代码的话,可能会看见timeout_add(), timeout_del(), timeout_initialized(),
timeout_set(),
timeout_pending()等。
  较老版本的Libevent(2.0之前)使用两个宏,完成event_get_fd和event_get_signal的工作:EVENT_FD和EVENT_SIGNAL。这些宏直接监测event结构的内部,因此在各种版本之间不具有二进制兼容性。在2.0以及之后的版本中,这些宏就是event_get_fd和event_get_signal函数的别名。
  在Libevent2.0之前的版本中不支持锁操作,因此,在运行base的线程之外的线程中,调用任何改变event状态的函数,都是不安全的。这些函数包括:event_add, event_del, event_active, 和 event_base_once。
  event_base_once的古老版本是event_once,它使用“当前”base的概念。
  在Libevent2.0之前,超时事件设置EV_PERSISIT是不明智的。并非在event激活时重置超时时间,EV_PERSISIT标志对于超时而言无任何作用。
  Libevent2.0之前的版本不支持多个events,在同一时间添加同样的fd以及相同的READ/WRITE事件。换句话说,对于每一个fd,一次只能有一个event在其上等待读或写。
以上就是libevent学习笔记【使用篇】(四)让events正常工作的全文介绍,希望对您学习和使用程序编程有所帮助.
这些内容可能对你也有帮助
更多可查看其它编程列表页。
猜您也会喜欢这些文章

我要回帖

更多关于 微信号查对方真实信息 的文章

 

随机推荐