Я использую libevent в backend-потоке, чтобы запустить hiredis и подписаться на удаленную базу данных redis. Подписка работает великолепно, используя простые примеры из другого SO вопроса:Как я могу сообщить потоку, выполняющему libevent, что он должен предпринять какие-то действия?
Однако для того, чтобы избежать условий гонки это не тривиально добавить подписки от основного потока. Для этого я создал объект std::vector<std::string>
, содержащий любые ключевые строки, на которые должен быть подписан бэкэнд. Чтение в/из этого вектора выполняется через мьютекс.
Однако, как я могу сообщить серверу, что я добавил некоторые подписки? В настоящее время я использую набор таймера для очень низкого разрешения:
void Client::fireAndRequeueTimer(int fd, short e, void* arg)
{
Client* client = reinterpret_cast<Client*>(arg); // the client handles the subscription to redis (via hiredis/libevent)
if (client->mDisconnect)
return; // the main thread wants us to exit, so we don't recreate the timer
event* ev = &client->mTimerEvent; // some timer event object we created
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000; // 1ms
evtimer_add(ev, &tv);
// mPendingSubscriptions is an std::vector of strings, which contain the keys that we should add subscriptions to.
if (client->mPendingSubscriptions.size())
{
std::unique_lock<std::mutex> lock(client->mSubscriptionsMutex);
do
{
redisAsyncCommand(
client->mContext,
Client::subCallback,
(char*)"sub",
"SUBSCRIBE %s",
client->mPendingSubscriptions.back().c_str());
client->mPendingSubscriptions.pop_back();
}
while (client->mPendingSubscriptions.size());
}
}
(обратите внимание, что я использую libevent 1.4.x
так такие функции, как EV_PERSIST не существует, и я должен воссоздать таймер в каждом случае).
Хотя выше работы, я не счастлив с ним по следующим причинам:
- Он помещает ненужное напряжение на внутреннем интерфейсе постоянно опрашивать вектор.
- Трудно читать читателю без подробных комментариев
- Это медленный; этот таймер добавит до 1 мс времени, необходимого для подписки на событие. Это может быть значительным, или это может быть не так, но в любом случае это пустая трата времени.
Есть ли решения этой проблемы, которые будут решать эти проблемы в пределах libevent 1.4.x
?
Не уверен, что libevent использует pthreads? Если да, можете ли вы использовать сигнал, например. SIGHUP и установите сигмас pthread, чтобы только ваш backend-поток принимал сигнал? –