libevent源码分析(四)

还是上次那个信号函数的例子, sample/signal-test.c——注册信号以及回调事件。
/* Initalize one event */
event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,&signal_int);
event_base_set(base, &signal_int);
以上函数为信号SIGINT注册是信号事件以及回调函数,然后设置Reactor对象base.
仔细看看源码:

void event_set(struct event *ev, int fd, short events,
               void (*callback)(int, short, void *), void *arg)
{
 /* Take the current base - caller needs to set the real base later */
 ev->ev_base = current_base;
 ev->ev_callback = callback;
 ev->ev_arg = arg;
 ev->ev_fd = fd;
 ev->ev_events = events;
 ev->ev_res = 0;
 ev->ev_flags = EVLIST_INIT;
 ev->ev_ncalls = 0;
 ev->ev_pncalls = NULL;
  min_heap_elem_init(ev);
   /* by default, we put new events into the middle priority */
 if(current_base)
  ev->ev_pri = current_base->nactivequeues/2;
}

将参数传入,替换为如下:

event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,&signal_int)
{
 /* Take the current base - caller needs to set the real base later */
 signal_int.ev_base = current_base;//current_base初始定义为NULL
 signal_int.ev_callback = signal_cb;//callback
 signal_int.ev_arg = &signal_int;//arg;
 signal_int.ev_fd = SIGINT;//fd;
 signal_int.ev_events = EV_SIGNAL|EV_PERSIST;//events;
 signal_int.ev_res = 0;
 signal_int.ev_flags = EVLIST_INIT;
 signal_int.ev_ncalls = 0;
 signal_int.ev_pncalls = NULL;
  min_heap_elem_init(&signal_int);
   /* by default, we put new events into the middle priority */
 if(current_base)
  signal_int.ev_pri = current_base->nactivequeues/2;
}

很直白,对struct event signal_int进行初始化,注意current_base是一个全局变量,类型为struct event_base*。创建struct event_base实体不光可以用event_base_new,也可用event_init,不过前者每次被调用创建一个独立的struct event_base实体,后者则会用新创建的struct event_base实体覆盖current_base,所以只要程序中涉及到current_base,那么就是基本上就是非线程安全的了,设想一下,有两个线程,分别创建两个struct event_base实体,current_base会被设置为其中一个实体,那么后面两个线程注册事件或者回调函数又抑或进行其他操作都是使用的同一个current_base实体,也就是两个线程原本都有自己独立的struct event_base实体,即Reactor,但是此时却共用一个struct event_base实体,程序执行情况无法预料,此时没有所谓的临界保护区,资源抢占或者串话都会导致程序异常。
event_set非常简单,就是替换掉current_base:

int event_base_set(base, &signal_int)
{
 /* Only innocent events may be assigned to a different base */
 if (signal_int.ev_flags != EVLIST_INIT)
  return (-1);
 signal_int.ev_base = base;
 signal_int.ev_pri = base->nactivequeues/2;
  return (0);
}

可以看见,原本signal_int.ev_base = current_base,现在current_base被替换掉了,在多线程中,确保每一个线程都有自己event_base,并且不要在线程里操作不是自己的event_base。从libevent-1.4源码来看,没有发现使用互斥锁,信号量等用来保护临界区的处理方式,好像2.0版本以上加入相应内容,在线程安全方面做了相应处理。

猜你喜欢

转载自blog.csdn.net/weixin_38134600/article/details/82809791