我正在使用libevent编写一个多线程应用程序。
一些事件是由IO触发的,但我需要几个由代码本身跨线程触发的事件,使用event_active()。
我试着写一个简单的程序来显示我的问题在哪里:
使用event_new()创建事件,并将fd设置为-1。
调用event_add()时,如果使用了超时结构,则事件稍后由event_base_dispatch正确处理。
如果使用event_add(ev, NULL)代替,它返回0(显然是成功的),但event_base_dispatch()返回1(这意味着没有正确注册事件)
此行为可以使用以下代码进行测试,并交换event_add行:
#include <event2/event.h>
#include <unistd.h>
void cb_func (evutil_socket_t fd, short flags, void * _param) {
puts("Callback function called!");
}
void run_base_with_ticks(struct event_base *base)
{
struct timeval one_sec;
one_sec.tv_sec = 1;
one_sec.tv_usec = 0;
struct event * ev1;
ev1 = event_new(base, -1, EV_PERSIST, cb_func, NULL);
//int result = event_add(ev1, NULL);
int result = event_add(ev1, &one_sec);
printf("event_add result: %dn",result);
while (1) {
result = event_base_dispatch(base);
if (result == 1) {
printf("Failed: event considered as not pending dispite successful event_addn");
sleep(1);
} else {
puts("Tick");
}
}
}
int main () {
struct event_base *base = event_base_new();
run_base_with_ticks(base);
return 0;
}
编译:g++示例。cc levent
问题是,我不需要超时,也不想使用n年的超时作为解决方案。因此,如果这不是使用用户触发事件的正确方式,我想知道它是如何完成的。
你的方法是合理的。在Libevent 2.0中,您可以使用event_active()从另一个线程激活事件。只要确保事先适当地使用evthread_use_windows_threads()或evthread_use_pthreads(),告诉Libevent使用正确的线程库。
至于需要额外的事件:在Libevent 2.0和更早的版本中,当没有添加挂起的事件时,事件循环将立即退出。您最好的选择可能是您发现的超时技巧。
如果你不喜欢这样,你可以使用内部的"event_base_add_virtual"函数告诉event_base它有一个虚拟事件。但是,这个函数没有导出,所以必须这样写:
void event_base_add_virtual(struct event_base *);
// ...
base = event_base_new();
event_base_add_virtual(base); // keep it from exiting
这是一个hack,但是,它使用了一个未记录的函数,所以你需要注意,以防它不能在Libevent的新版本中工作。
最后,这个方法现在对你没有帮助,但是Libevent的未来版本(2.1和更高版本)有一个补丁等待,它将向event_base_loop()添加一个新标志,以防止它在循环超出事件时退出。这个补丁已经在Github上发布了;它主要是等待代码审查,并等待一个更好的名称。
我刚刚被libbevent -2.0.21-stable烫伤了。很明显这是一个bug。我希望他们在未来的版本中修复它。与此同时,更新文档以警告我们这一点将是有帮助的。
最好的解决方法似乎是问题中描述的假超时。
@nickm,你没有读问题。他的示例代码像您描述的那样使用event_new();libevent中有一个bug,当使用NULL超时时导致它失败(但当您调用event_add()时返回0)。