Событие, вызванное Пользователем в libevent
в настоящее время я пишу многопоточное приложение с использованием libevent.
некоторые события запускаются IO, но мне нужно несколько событий, которые запускаются через потоки самим кодом, используя event_active ().
я попробовал написать простую программу, которая показывает, где моя проблема:
событие создается с помощью event_new (), а значение fd равно -1.
при вызове event_add (), если используется структура timeout, событие происходит позже правильно обработано 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++ sample.cc -Левент!--2-->
дело в том, что мне не нужен тайм-аут и я не хочу использовать тайм-аут n-years в качестве обход. Поэтому, если это неправильный способ использования пользовательских событий, я хотел бы знать, как это делается.
2 ответов
ваш подход-это звук. В 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
это немного Хак, хотя, и он использует недокументированную функцию, поэтому вам нужно будет следить, если он не работает с более поздней версией Libevent.
наконец, этот метод не поможет вам сейчас, но есть патч в ожидании будущих версий Libevent (2.1 и более поздних), чтобы добавить новый флаг в event_base_loop (), чтобы он не выходил, когда цикл выходит из событий. Патч на Github; он в основном ждет обзора кода и лучшего имени для опции.
Я только что обжегся этим с libevent-2.0.21-stable. Совершенно очевидно, что это ошибка. Я надеюсь, что они исправят это в будущем выпуске. Тем временем, обновление документов, чтобы предупредить нас об этом, было бы полезно.
лучшим обходным путем, по-видимому, является поддельный тайм-аут, как описано в вопросе.
@nickm, вы не читали вопрос. Его пример кода использует event_new (), как вы описали; в libevent есть ошибка, которая приводит к сбою при использовании таймаута NULL (но возвращает 0 при вызове event_add ()).