C ++ libhiredis с libev и настраиваемым циклом событий

Мое приложение использует libhiredis с бэкэндом libev. Мне нужно отправить асинхронные команды Redis и обработать полученный асинхронный обратный вызов Redis. Однако, в отличие от простого примера из здесь, я не могу используйте цикл событий по умолчанию. Следующий код приближает пример с настраиваемым циклом событий. Однако при компиляции только с redisLibevAttach() индуцированным наблюдателем libev io поток цикла обработки событий немедленно завершается. Вы можете увидеть это, запустив

g++ -g -std=c++11 -Wall -Wextra -Werror hiredis_ev.cpp -o hiredis_ev -lpthread -lhiredis -lev && gdb ./hiredis_ev

где GDB радостно печатает, что новый поток создан и почти сразу завершается. Это дополнительно подтверждается запуском info thread в GDB, который не показывает my_ev_loop. Однако, если я изменю код, добавив какой-либо другой наблюдатель libev, например таймер, то все будет хорошо. Вы можете увидеть это, запустив

g++ -g -DTIMER -std=c++11 -Wall -Wextra -Werror hiredis_ev.cpp -o hiredis_ev -lpthread -lhiredis -lev &&  ./hiredis_ev

Мне не нужен фиктивный таймер libev для работы цикла событий. Что мне не хватает?

#include <iostream>
#include <thread>
#include <hiredis/hiredis.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libev.h>

static struct ev_loop *loop = nullptr;
static void redis_async_cb(redisAsyncContext *, void *, void *)
{
  std::cout << "Redis async callback" << std::endl;
  fflush(nullptr);
}

#ifdef TIMER
  static ev_timer timer_w;
  static void ev_timer_cb(EV_P_ ev_timer *, int)
  {
    std::cout << "EV timer callback" << std::endl;
    fflush(nullptr);
  }
#endif

int main()
{
  loop = ev_loop_new(EVFLAG_AUTO);

#ifdef TIMER
  ev_timer_init(&timer_w, ev_timer_cb, 0, 0.1);
  ev_timer_start(loop, &timer_w);
#endif

  redisAsyncContext* async_context = redisAsyncConnect("localhost", 6379);
  if (nullptr == async_context)
  {
    throw std::runtime_error("No redis async context");
  }

  redisLibevAttach(loop, async_context);
  std::thread ev_thread(ev_run, loop, 0); 
  pthread_setname_np(ev_thread.native_handle(), "my_ev_loop");
  ev_thread.detach();

  // Give the event loop time to start
  while (!ev_iteration(loop))
  {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }

  // Send a SUBSCRIBE message which should generate an async callback
  if (REDIS_OK != redisAsyncCommand(async_context, redis_async_cb, nullptr, "SUBSCRIBE foo"))
  {
    throw std::runtime_error("Could not issue redis async command");
  }
  std::cout << "Waiting for async callback" << std::endl;
  fflush(nullptr);
    fflush(nullptr);

  // Wait forever (use CTRL-C to terminate)
  while (true)
  {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }

  return 0;
}

person Paul Grinberg    schedule 08.05.2020    source источник


Ответы (1)


Я узнал, что у сообщества hiredis есть собственный экземпляр GitHub, где я могу задавать вопросы. Поскольку здесь я еще не получил ответа, я спросил там. Ответ можно найти на странице https://github.com/redis/hiredis/issues/801#issuecomment-626400959

person Paul Grinberg    schedule 11.05.2020