Событие, инициированное пользователем в libevent - PullRequest
8 голосов
/ 04 октября 2011

В настоящее время я пишу многопоточное приложение с использованием 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-летний тайм-аут в качестве обходного пути. Поэтому, если это неправильный способ использования событий, инициируемых пользователем, я хотел бы знать, как это делается.

Ответы [ 2 ]

8 голосов
/ 04 октября 2011

Ваш подход здоров.В 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 ;в основном он ожидает проверки кода и более точного названия опции.

1 голос
/ 28 апреля 2014

Я просто сгорел от этого с libevent-2.0.21-stable. Это довольно ясно, ошибка. Я надеюсь, что они исправят это в будущем выпуске. Тем временем было бы полезно обновить документы, чтобы предупредить нас об этом.

Лучший обходной путь - это поддельное время ожидания, как описано в вопросе.

@ nickm, вы не читали вопрос. Его пример кода использует event_new (), как вы описали; в libevent есть ошибка, которая приводит к сбою при использовании NULL-таймаута (но возвращает 0 при вызове event_add ()).

...