Libevent官方代码样例学习(一)
在Ubuntu16.04中, libevent的默认安装位置为
#在 trusty 发行版中 amd64 硬件架构下的 libevent-2.0- 软件包文件清单
/usr/lib/x86_64-linux-gnu/libevent-2.0.so.
/usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.
/usr/share/doc/libevent-2.0-/changelog.Debian.gz
/usr/share/doc/libevent-2.0-/copyright
https://github.com/libevent/libevent/blob/master/sample/time-test.c
这是一个定时触发事件的例子, 根据输入参数的不同, 单次执行或持续执行.
在main方法中, 通过以下的方法调用将timeout_event加入到将来的事件中.
base = event_base_new();
struct event timeout;
event_assign(&timeout_event, base, -, flags, timeout_callback, (void *) &timeout_event);
event_add(timeout_event, &tv);
event_base_dispatch(base);
将timeout_event作为参数传入callback方法, 然后在callback方法中再次将timeout_event加入到将来的事件中
struct event *timeout_event = arg;
// ...
event_add(timeout_event, &tv);
在这种情况下, 原代码中的flags = EV_PERSIST其实是不起作用的, 因为callback中复用了原来的内存地址, 设置为flags = 0一样能持续执行.
如果将event_assign改为event_new, 则调用变为
base = event_base_new();
// 注意此处不传入event而传入event_base, 因为event在当前方法中new并alloca空间, 所以传入的event指针是无效的.
struct event *timeout_event = event_new(base, -, flags, timeout_callback, base);
event_add(timeout_event, &tv);
evutil_gettimeofday(&lasttime, NULL);
event_base_dispatch(base);
而callback中的处理变为
struct event_base *base = arg;
struct event *timeout_event = event_new(base, -, , timeout_callback, base);
event_add(timeout_event, &tv);
这时候, 如果代码中使用flags = EV_PERSIST就会产生内存泄漏, 因为在触发后并不释放, 会持续的每隔1秒调用callback, 这时候要么在callback中不新增event, 要么flag设为0.
修改后的代码:
/*
* XXX This sample code was once meant to show how to use the basic Libevent
* interfaces, but it never worked on non-Unix platforms, and some of the
* interfaces have changed since it was first written. It should probably
* be removed or replaced with something better.
*
* Compile with:
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
*/ #include <sys/types.h> #ifndef _WIN32
#include <sys/queue.h>
#include <unistd.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif #include <stdio.h>
#include <string.h> #include <event2/event.h>
#include <event2/event_struct.h> #ifdef _WIN32
#include <winsock2.h>
#endif struct timeval lasttime;
int event_is_persistent; static void
timeout_callback(evutil_socket_t fd, short event, void *arg) {
struct timeval newtime, difference;
struct event_base *base = arg;
double elapsed; // The evutil_gettimeofday function sets tv to the current time. The second argument is unused.
evutil_gettimeofday(&newtime, NULL);
// This macro subtract (respectively) their first two arguments, and stores the result in the third.
evutil_timersub(&newtime, &lasttime, &difference);
elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6);
printf("timeout_callback called at %d: %.3f seconds elapsed.\n", (int) newtime.tv_sec, elapsed);
lasttime = newtime;
if (event_is_persistent == ) {
struct event *timeout_event = event_new(base, -, , timeout_callback, base);
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = ;
tv.tv_usec = ;
event_add(timeout_event, &tv);
}
} int
main(int argc, char **argv) {
struct timeval tv;
struct event_base *base;
int flags;
// strcmp: <0 the first character that does not match has a lower value in ptr1 than in ptr2
// 0 the contents of both strings are equal
// >0 the first character that does not match has a greater value in ptr1 than in ptr2
if (argc == && !strcmp(argv[], "-p")) {
event_is_persistent = ;
// Use this if you use event_new instead of event_assign
flags = 0;
} else {
event_is_persistent = ;
flags = ;
}
/* Initalize the event library */
base = event_base_new();
/*
* Prepare a new, already-allocated event structure to be added.
* The function event_assign() prepares the event structure ev to be used in future calls to event_add() and event_del().
* Unlike event_new(), it doesn't allocate memory itself: it requires that you have already allocated a struct event,
* probably on the heap. Doing this will typically make your code depend on the size of the event structure, and thereby
* create incompatibility with future versions of Libevent.
* The easiest way to avoid this problem is just to use event_new() and event_free() instead.
* A slightly harder way to future-proof your code is to use event_get_struct_event_size() to determine the required size
* of an event at runtime.
* Note that it is NOT safe to call this function on an event that is active or pending. Doing so WILL corrupt internal
* data structures in Libevent, and lead to strange, hard-to-diagnose bugs. You can use event_assign to change an existing
* event, but only if it is not active or pending!
*/
//event_assign(&timeout_event, base, -1, flags, timeout_callback, (void *) &timeout_event);
struct event *timeout_event = event_new(base, -, flags, timeout_callback, base); // Set (tvp)->tv_sec and (tvp)->tv_usec to 0
evutil_timerclear(&tv);
tv.tv_sec = ;
// Add an event to the set of pending events.
// The function event_add() schedules the execution of the ev event when the event specified in event_assign()/event_new() occurs,
// or when the time specified in timeout has elapesed. If atimeout is NULL, no timeout occurs and the function will only be called
// if a matching event occurs. The event in the ev argument must be already initialized by event_assign() or event_new() and may
// not be used in calls to event_assign() until it is no longer pending.
// If the event in the ev argument already has a scheduled timeout, calling event_add() replaces the old timeout with the new one,
// or clears the old timeout if the timeout argument is NULL.
event_add(timeout_event, &tv);
evutil_gettimeofday(&lasttime, NULL);
event_base_dispatch(base); return ();
}
Update 2017-12-05:
如果使用的是libevent 2.1.1以后的版本, 可以使用event_self_cbarg()方法. 在event_new中通过 event_self_cbarg() 方法传入自身指针.
#include <event2/event.h>
static int n_calls = ; void cb_func(evutil_socket_t fd, short what, void *arg){
struct event *me = arg;
printf("cb_func called %d times so far.\n", ++n_calls);
if (n_calls > )
event_del(me);
} void run(struct event_base *base){
struct timeval one_sec = { , };
struct event *ev;
/* We're going to set up a repeating timer to get called called 100 times. */
ev = event_new(base, -, EV_PERSIST, cb_func, event_self_cbarg());
event_add(ev, &one_sec);
event_base_dispatch(base);
}
Libevent官方代码样例学习(一)的更多相关文章
- Libevent官方代码样例学习(二)
连接监听器: 接收TCP连接请求 evconnlistener机制用于监听并接受TCP连接请求. 这些方法在event2/listener.h中声明, 在Libevent 2.0.2-alpha之后的 ...
- scrapy爬虫学习系列二:scrapy简单爬虫样例学习
系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备: http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...
- 33个超级有用必须要收藏的PHP代码样例
作为一个正常的程序员,会好几种语言是十分正常的,相信大部分程序员也都会编写几句PHP程序,如果是WEB程序员,PHP一定是必备的,即使你没用开发过大型软件项目,也一定多少了解它的语法. 在PHP的流行 ...
- java servlet 代码样例 (demo)
今天又搞了下jsp +servlet 的代码样例,感觉虽然搭了好多次,可是每次还是不记得那些参数,都要去网上搜索,索性自己把这次的简单demo给记录下来,供下次使用的时候直接复制吧. 这个web逻辑 ...
- 模式识别 - 处理多演示样例学习(MIL)特征(matlab)
处理多演示样例学习(MIL)特征(matlab) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27206325 多演示样例学习( ...
- 2020JAVA最新应对各种OOM代码样例及解决办法
引言 作者:黄青石 链接:https://www.cnblogs.com/huangqingshi/p/13336648.html?utm_source=tuicool&utm_medium= ...
- zookeeper实战:SingleWorker代码样例
我们需要一个“单点worker”系统,此系统来确保系统中定时任务在分布式环境中,任意时刻只有一个实例处于活跃:比如,生产环境中,有6台机器支撑一个应用,但是一个应用中有30个定时任务,这些任务有些必须 ...
- 30个php操作redis经常用法代码样例
这篇文章主要介绍了30个php操作redis经常用法代码样例,本文事实上不止30个方法,能够操作string类型.list类型和set类型的数据,须要的朋友能够參考下 redis的操作非常多的,曾经看 ...
- JAVA各种OOM代码样例及解决方法
周末了,觉得我还有很多作业没有写,针对目前大家对OOM的类型不太熟悉,那么我们来总结一下各种OOM出现的情况以及解决方法. 我们把各种OOM的情况列出来,然后逐一进行代码编写复现和提供解决方法. 1. ...
随机推荐
- 洛谷 P3386 【模板】二分图匹配
题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 ...
- C#多线程写日志
由于程序是3层架构的,所有多线程记录日志成了比较棘手的问题,以前还真就没有在意过写日志的问题,认为不过是写文件罢了~~!如今发现原来要实现文件共享,并且能够使多线程同时操作日志还不能相互冲突,真的很麻 ...
- C++11 std::shared_ptr总结与使用
最近看代码,智能指针用的比较多,自己平时用的少,周末自己总结总结.方便后续使用. std::shared_ptr大概总结有以下几点: (1) 智能指针主要的用途就是方便资源的管理,自动释放没有指针引用 ...
- jQuery EasyUI Datagrid性能优化专题(转)
jQuery EasyUI的Datagrid组件功能算是很强大了,不过性能确实不怎么乐观,而对于性能问题,网络上几乎也找不到相关的优化资料,所谓的牛人们可能 都望而却步了.本博客以后会带着分析Dat ...
- 使用MDS Switch基本命令的一个例子
笔者有幸摆弄一套vBlock的环境, 刚刚接手, 对其上的很多配置都不了解. 下面我们就例举一下我们通过运行哪些命令来搞清楚我们的UCS是如何连接到VNX storage array上的. 首先, 通 ...
- 如何让Domain里的其他系统通过DC来进行外网的DNS解析
搭建一个测试环境, 一般会建立一个DC, 然后再建立许多虚机加入到这个新DC的domain. 我们有个DNS服务器的地址, 哪台虚机要上外网, 就把这个DNS地址填到这台虚机的DNS server a ...
- Spring(二十):Spring AOP(四):基于配置文件的方式来配置 AOP
基于配置文件的方式来配置 AOP 前边三个章节<Spring(十七):Spring AOP(一):简介>.<Spring(十八):Spring AOP(二):通知(前置.后置.返回. ...
- servlet种下cookie后如何携带cookie继续往下走
事情是这样的,今天我在应用1里面手动种下了一个cookie,然后它会发接着访问应用2,因为是我手动setCookie,所以它还没来得及携带cookie继续前往下一站,于是,apple pen,炸了. ...
- easyui datagrid实现拖动表头
$.extend($.fn.datagrid.methods, { columnMoving: function (jq) { return jq.each(function () { var tar ...
- [Canvas]走近的女孩
动态效果请点此下载文件并使用Chrome或者FireFox浏览器观看. 图例: 代码: <!DOCTYPE html> <html lang="utf-8"> ...