【发布时间】:2015-09-06 07:57:47
【问题描述】:
我在后端线程中使用 libevent 来运行hiredis 并订阅远程redis 数据库。使用另一个 SO 问题中的简单示例,订阅效果非常好:
但是,为了避免竞争条件,从主线程添加订阅并非易事。为了实现这一点,我创建了一个 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 等功能,我必须在每个事件中重新创建计时器)。
虽然上述方法有效,但我对此并不满意,原因如下:
- 它给后端带来了不必要的压力以不断地轮询向量。
- 如果没有大量的 cmets,读者很难理解
- 很慢;这个计时器将增加多达 1 毫秒的时间来订阅一个事件。这可能很重要,也可能不重要,但无论如何都是浪费时间。
在libevent 1.4.x 的范围内,是否有任何解决方案可以解决这些问题?
【问题讨论】:
-
不确定 libevent 是否使用 pthreads?如果是这样,您可以使用信号吗,例如SIGHUP,并设置 pthread sigmask,以便只有您的后端线程会接受信号?