libevent源码深度剖析十三
——libevent信号处理注意点
前面讲到了libevent实现多线程的方法,然而在多线程的环境中注册信号事件,还是有一些情况需要小心处理,那就是不能在多个libevent实例上注册信号事件。依然冠名追加到libevent系列。
以2个线程为例,做简单的场景分析。
1 首先是创建并初始化线程1的libevent实例base1,线程1的libevent实例base2;
2 在base1上注册SIGALRM信号;在base2上注册SIGINT信号;
3 假设当前base1和base2上都没有注册其他的事件;
4 线程1和2都进入event_base_loop事件循环:
event_base_loop(base1) event_base_loop(base2)
{ {
if (base2->sig.ev_signal_added) if (base2->sig.ev_signal_added)
evsignal_base = base1; evsignal_base = base2;
while(!done) while(!done)
{ {
… …
evsel->dispatch(…); evsel->dispatch(…);
… …
} }
} }
5 假设线程1先进入event_base_loop,并设置evsignal_base = base1;并等待;
6 接着线程2也进入event_base_loop,并设置evsignal_base = base2;并等待;
于是evsignal_base就指向了base2;
7 信号ALARM触发,调用服务例程:
static void evsignal_handler(int sig)
{
...
evsignal_base->sig.evsigcaught[sig]++;
evsignal_base->sig.evsignal_caught= 1;
/*Wake up our notification mechanism */
send(evsignal_base->sig.ev_signal_pair[0],"a", 1, 0);
...
}
于是base2得到通知ALARM信号发生了,而实际上ALARM是注册在base1上的,base2上的ALARM注册event是空的,于是处理函数将不能得到调用;
因此在libevent中,如果需要处理信号,只能将信号注册到一个libevent实例上。
memcached就没有使用libevent提供的signal接口,而是直接使用系统提供的原生API,看起来这样更简洁。