Событие, вызванное Пользователем в 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 ()).