libevent(7)libevent中的事件event

一、事件状态

libevent有4种事件状态,分别是: initialized、pending、active、persistent。这4种状态的转换关系如下:

1、已初始化(initialized):对应图中的non-pending状态,表示事件已经新建完成,但是还未添加到了libevent 队列中。有 4 种方法可以让事件跳转到此状态:

(1)调用 event_new 函数,返回一个事件对象,或调用 event_assign 赋值一个事件对象。

struct event *event_new(
    struct event_base *, evutil_socket_t, short, event_callback_fn, void *);

int event_assign(struct event *, 
    struct event_base *, evutil_socket_t, short, event_callback_fn, void *);

// 回调函数指针定义
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);

(2)pinding 状态的事件调用event_del函数后。

(3)active 状态的事件调用完成(即执行完事件回调函数),若没有定义持久化。

2、待决(pending):此状态表示事件已经位于libevent 队列中,可以随时准备执行。有 4 种方法可以让事件跳转到此状态:

(1)调用 event_add 之后。

(2)active 状态的事件调用完成(即执行完事件回调函数),若定义为持久化。

3、激活(active):此状态表示事件正在执行中,也包括超时事件。这是由 libevent 进行调度的,用户也可以手动调用 event_active 函数让事件转为此状态。

4、持久的(persistent):

(1)若定义为持久化,事件完成后状态会由 active 变为 pending ,可仍由 libevent 调用,不用做其他操作;

(2)若未定义为持久化,则表示事件完成后状态会由 active 变为 non-pending ,即初始化状态(initialized)。此时需要再次调用 event_add 函数,将事件变为 pending 状态,事件才会再次被执行。

二、例子

1、下面我们来看一个完整的例子 test_signal.cpp:


#include <iostream>
#include <string.h>
#include <signal.h>
#include <event2/event.h>
#include <event2/listener.h>

#define PORT 5001

using namespace std;

//socket 文件描述符
//which 事件类型
//arg 传递的参数 
static void Ctrl_C(int socket, short which, void* arg){
    cout<<"Ctrl_C"<<endl;
}

int main()
{   
    //创建libevent上下文
    event_base* base = event_base_new();
    if (base) {
        cout<<"event_base_new success!"<<endl;
    }

	//添加ctrl +c信号事件,处于no_pending状态
	event *csig = evsignal_new(base, SIGINT, Ctrl_C, base);
	if(!csig){
	    cerr<<"evsignal_new failed!"<<endl;
		return -1;
	}

	//添加事件到pending
	if(event_add(csig, 0) != 0){
	    cerr <<"event_add failed!"<< endl;
		return -1;
	}
	
    //事件分发处理
    if (base) {
        event_base_dispatch(base);
    }
	
    if (csig) {
	    event_free(csig);
	}
	
    if (base) {
        event_base_free(base);
    }

    return 0;
}

运行结果如下:

2、下面我们把这个例子再深化一下,添加下其他event:


#include <iostream>
#include <string.h>
#include <signal.h>
#include <event2/event.h>
#include <event2/listener.h>

#define PORT 5001

using namespace std;

//socket 文件描述符
//which 事件类型
//arg 传递的参数 
static void Ctrl_C(int socket, short which, void* arg){
    cout<<"Ctrl_C"<<endl;
}

static void Kill(int socket, short which, void* arg){
    cout<<"Kill"<<endl;
	
	//加上下面这段代码后,event又变被重新pending
	event* ev = (event*)arg;
	if(!evsignal_pending(ev, NULL)){
	    event_del(ev);
		event_add(ev, NULL);
	}
}

int main()
{   
    //创建libevent上下文
    event_base* base = event_base_new();
    if (base) {
        cout<<"event_base_new success!"<<endl;
    }

	//添加ctrl +c信号事件,处于no_pending状态
	//evsignal_new隐藏的状态: EV_SIGNAL|EV_PERSIST
	event *csig = evsignal_new(base, SIGINT, Ctrl_C, base);
	if(!csig){
	    cerr<<"evsignal_new csig failed!"<<endl;
		return -1;
	}

	//添加事件到pending
	if(event_add(csig, 0) != 0){
	    cerr <<"event_add csig failed!"<< endl;
		return -1;
	}
	
	//添加kill信号
	//EV_SIGNAL: 没有添加EV_PERSIST,表面当前event为非持久化事件,只能执行1次
	//event_self_cbarg(): 传递当前的event
	event *ksig = event_new(base, SIGTERM, EV_SIGNAL, Kill, event_self_cbarg());
	if(!ksig){
	    cerr<<"event_new ksig failed!"<<endl;
		return -1;
	}

	//添加事件到pending
	if(event_add(ksig, 0) != 0){
	    cerr <<"event_add ksig failed!"<< endl;
		return -1;
	}
	
    //事件分发处理
    if (base) {
        event_base_dispatch(base);
    }
	
    if (csig) {
	    event_free(csig);
	}
	
    if (base) {
        event_base_free(base);
    }

    return 0;
}

执行结果如下:

参考:

Libevent 学习四:事件状态和事件处理
https://blog.csdn.net/myw31415926/article/details/127372808

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libevent是一个高效的事件通知,可以用于多线程环境下的事件驱动编程。下面介绍一下libevent在多线程的使用方法: 1. 创建event_base对象 在多线程环境下,每个线程需要创建一个event_base对象来管理其事件。可以使用event_base_new函数来创建event_base对象。 2. 创建事件 可以使用event_new函数来创建事件。需要指定事件类型、事件触发方式、事件处理函数等参数。 3. 注册事件 在创建事件之后,需要将事件注册到event_base对象上。可以使用event_add函数将事件添加到event_base对象。 4. 事件循环 在多线程环境下,每个线程需要运行自己的事件循环。可以使用event_base_loop函数启动事件循环。该函数会一直阻塞,直到事件触发或者事件循环被停止。 5. 停止事件循环 可以使用event_base_loopbreak函数停止事件循环。该函数会唤醒正在阻塞的事件循环,并使其退出。 6. 销毁event_base对象 在使用完event_base对象之后,需要调用event_base_free函数来销毁对象。该函数会释放对象占用的内存。 总之,libevent在多线程环境下的使用需要注意以下几点: 1. 每个线程需要创建自己的event_base对象。 2. 在创建事件时,需要保证事件的处理函数是线程安全的。 3. 在注册事件时,需要将事件添加到正确的event_base对象。 4. 在事件循环,需要处理好线程间的同步问题。 5. 在退出程序时,需要销毁所有的event_base对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值