Libevent 是一个轻量级的开源高性能网络库,事件驱动(event-driven), 实现基于 Reactor 模式,网上学习资料众多,这里分享一下关于 signal 的处理。
首先给出 libevent 对 signal 的处理宏定义:
evsignal_* macros
Aliases for working with signal events
#define evsignal_add(ev, tv) event_add((ev), (tv))
#define evsignal_assign(ev, b, x, cb, arg) \
event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg))
#define evsignal_new(b, x, cb, arg)\
event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
#define evsignal_del(ev) event_del(ev)
#define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv))
#define evsignal_initialized(ev) event_initialized(ev)
signal 事件的处理函数即是普通 event 事件的处理函数别无二致,唯一不同之处在于在文件描述符,signal 事件该参数的意义是 signal no,我们可以用 kill -l 命令查看系统的 signal table:
常用的信号 有SIGINT ( CTRL+C),SINPIPE(经常用于网络编程)。
我这里先写一个例子:
#include <stdio.h>
#include <stdlib.h>
#include <event2/event.h>
#include <event2/event_struct.h>
void handler(int signo, short events, void* arg) {
printf("Receive signal %d\n", signo);
}
int main()
{
struct event_base* base = event_base_new();
int signo = SIGINT;
struct event *sig_event = evsignal_new(base, signo, handler, NULL);
evsignal_add(sig_event, NULL);
event_base_dispatch(base);
exit(0);
}
这里我以SIGINT信号为例,首先写一个信号处理函数
void handler(int signo, short events, void* arg)
该函数的形参与一般的回调函数无异,处理内容也很简单,就是打印出收到的 signal,当然真实情况需要做更适当的处理。
上面的代码处理很简单:
首先新建一个 event 变量用于处理信号
struct event * sig_event = evsignal_new(base, signo, handler, NULL);
接着将它注册到信号事件队列
evsignal_add(sig_event, NULL);
剩下的就和普通事件完全一样了。
编译:
gcc -o proc event-signal-demo.c -levent
运行测试:
按下 CTRL + C会发现程序不会像平常那般退出,而是打印出
“^CReceive signal 2”
程序捕捉到了 SIGINT 信号,over。
此外讨论一下,如何对特定的线程发出特定的信号,仍以上面的程序为例,除了采用CTRL + C产生 SIGINT 信号外,更一般的方法是借助 kill 命令。
首先先求得目的线程的 PID,利用如下命令:
ps aux | grep proc | grep -v grep
在结果中得出 proc 进程的 PID 为2719。接着使用
kill -2 2719
就可以向 proc 进程发送 SIGINT 信号了(这里的2是 SIGINT 的 signo)。
允许转载
参考资料
libevent源码深度剖析 张亮
Fast portable non-blocking network programming with Libevent (没发现作者是谁)