libevent 中的用户触发事件
我目前正在使用 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: %d\n",result);
while (1) {
result = event_base_dispatch(base);
if (result == 1) {
printf("Failed: event considered as not pending dispite successful event_add\n");
sleep(1);
} else {
puts("Tick");
}
}
}
int main () {
struct event_base *base = event_base_new();
run_base_with_ticks(base);
return 0;
}
编译: g++sample.cc -levent
问题是,我不需要超时,并且不想使用 n 年超时作为解决方法。因此,如果这不是使用用户触发事件的正确方法,我想知道它是如何完成的。
I am currently writing a multi-threaded application using libevent.
Some events are triggered by IO, but I need a couple of events that are triggered accross threads by the code itself, using event_active().
I have tried to write a simple program that shows where my problem is:
The event is created using event_new(), and the fd set to -1.
When calling event_add(), if a timeout struct is used, the event is later properly handled by event_base_dispatch.
If event_add(ev, NULL) is used instead, it returns 0 (apparently successful), but event_base_dispatch() returns 1 (which means no the event was not properly registered.)
This behavior can be tested using the following code and swapping the event_add lines:
#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: %d\n",result);
while (1) {
result = event_base_dispatch(base);
if (result == 1) {
printf("Failed: event considered as not pending dispite successful event_add\n");
sleep(1);
} else {
puts("Tick");
}
}
}
int main () {
struct event_base *base = event_base_new();
run_base_with_ticks(base);
return 0;
}
Compilation: g++ sample.cc -levent
The thing is, I do not need the timeout, and do not want to use a n-years timeout as a workaround. So if this is not the right way to use user-triggered events, I would like to know how it is done.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你的方法是正确的。在 Libevent 2.0 中,您可以使用 event_active() 从另一个线程激活事件。只需确保事先适当使用 evthread_use_windows_threads() 或 evthread_use_pthreads() 来告诉 Libevent 使用正确的线程库。
至于需要额外的事件:在Libevent 2.0及更早版本中,当没有添加待处理事件时,事件循环将立即退出。你最好的选择可能就是你发现的超时技巧。
如果您不喜欢这样,您可以使用内部“event_base_add_virtual”函数告诉 event_base 它有一个虚拟事件。不过,这个函数没有导出,所以你必须这样说:
That's a bit of a hack, but, and it using an undocumented function, so you'd need to watch out in case it does not work使用更高版本的 Libevent。
最后,这个方法现在对你没有帮助,但是 Libevent 的未来版本(2.1 及更高版本)有一个补丁正在等待,以向 event_base_loop() 添加一个新标志,以防止它在循环退出事件时退出。该补丁在Github上;主要是等待代码审查,以及为该选项取一个更好的名称。
Your approach is sound. In Libevent 2.0, you can use event_active() to activate an event from another thread. Just make sure that you use evthread_use_windows_threads() or evthread_use_pthreads() as appropriate beforehand, to tell Libevent to use the right threading library.
As for needing an extra event: in Libevent 2.0 and earlier, an event loop will exit immediately when there are no pending events added. Your best bet there is probably the timeout trick you discovered.
If you don't like that, you can use the internal "event_base_add_virtual" function to tell the event_base that it has a virtual event. This function isn't exported, though, so you'll have to say something like:
That's a bit of a hack, though, and it uses an undocumented function, so you'd need to watch out in case it doesn't work with a later version of Libevent.
Finally, this method won't help you now, but there's a patch pending for future versions of Libevent (2.1 and later) to add a new flag to event_base_loop() to keep it from exiting when the loop is out of events. The patch is over on Github; it is mainly waiting for code review, and for a better name for the option.
我刚刚被 libevent-2.0.21-stable 搞得焦头烂额。这显然是一个错误。我希望他们在未来的版本中修复它。同时,更新文档以警告我们这一点将会有所帮助。
最好的解决方法似乎是问题中描述的假超时。
@nickm,你没有阅读这个问题。他的示例代码使用 event_new() 就像您所描述的那样; libevent 中有一个错误,导致它在使用 NULL 超时时失败(但在调用 event_add() 时返回 0)。
I just got burned by this with libevent-2.0.21-stable. It is quite clearly a bug. I hope they fix it in a future release. In the meantime, updating the docs to warn us about it would be helpful.
The best workaround seems to be the fake timeout as described in the question.
@nickm, you didn't read the question. His example code uses event_new() like you described; there is a bug in libevent that causes it to fail when using a NULL timeout (but return 0 when you call event_add()).