如何通知运行 libevent 的线程它应该采取一些措施?
Posted
技术标签:
【中文标题】如何通知运行 libevent 的线程它应该采取一些措施?【英文标题】:How can I inform a thread running libevent that it should take some action? 【发布时间】:2015-09-06 07:57:47 【问题描述】:我在后端线程中使用 libevent 来运行hiredis 并订阅远程redis 数据库。使用另一个 SO 问题中的简单示例,订阅效果非常好:
Hiredis waiting for message
但是,为了避免竞争条件,从主线程添加订阅并非易事。为了实现这一点,我创建了一个 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,以便只有您的后端线程会接受信号? 【参考方案1】:就我个人而言,我更喜欢让目标线程在其事件队列中添加一个eventfd
(或类似结构)。
eventfd
可以从任何其他线程安全地通知,并导致目标线程调用相关的事件处理程序。
这样,您无需担心正确锁定 libevent 结构的绝对最小值,因为操作系统会为您处理这些问题。
注意:eventfd
在 OSX 上不可用,但只要您不需要极高的事件率,就可以使用管道轻松模拟。
【讨论】:
这听起来像我需要的。我猜我需要使用event_set(&event, fd, EV_READ, fn, data)
之类的东西,但是我该如何 a) 获取 fd
和 b) "touch" fd 来触发事件?
我应该澄清一下;我正在寻求一个尽可能便携的解决方案,所以我想尽可能避免系统调用。
有evutil_socketpair
应该创建一个类似的解决方案,我承认我从未尝试过。以上是关于如何通知运行 libevent 的线程它应该采取一些措施?的主要内容,如果未能解决你的问题,请参考以下文章
libevent 是不是允许在不同的线程中运行定时器/io 的回调?