使用set_alert_notify唤醒主线程的正确方法是什么?



>我正在尝试基于 libtorrent 栅格栏编写自己的种子程序,但在使警报机制正常工作时遇到问题。Libtorrent提供功能

void set_alert_notify (boost::function<void()> const& fun);

这应该是

该函数的目的是客户端唤醒其主线程,以使用 pop_alerts(( 轮询更多警报。如果通知函数未能执行此操作,则不会再次调用它,直到出于其他原因调用pop_alerts。

到目前为止一切顺利,我想我理解这个功能背后的意图。但是,我的实际实现效果不佳。到目前为止,我的代码是这样的:

std::unique_lock<std::mutex> ul(_alert_m);
session.set_alert_notify([&]() { _alert_cv.notify_one(); });
while (!_alert_loop_should_stop) {
if (!session.wait_for_alert(std::chrono::seconds(0))) {
_alert_cv.wait(ul);
}
std::vector<libtorrent::alert*> alerts;
session.pop_alerts(&alerts);
for (auto alert : alerts) {
LTi_ << alert->message();
}
}

但是存在竞争条件。如果wait_for_alert返回NULL(因为还没有警报(,但传递给set_alert_notify的函数在_alert_cw.wait(ul);之前被调用,整个循环将永远等待(因为引用中的第二句话(。

目前,我的解决方案只是将_alert_cv.wait(ul);更改为_alert_cv.wait_for(ul, std::chrono::milliseconds(250));,从而减少每秒循环次数,同时保持足够低的延迟。

但这确实是比解决方案更多的解决方法,我一直认为必须有适当的方法来处理这个问题。

您需要一个变量来记录通知。它应该受到拥有条件变量的同一互斥锁的保护。

bool _alert_pending;
session.set_alert_notify([&]() {
std::lock_guard<std::mutex> lg(_alert_m);
_alert_pending = true;
_alert_cv.notify_one();
});
std::unique_lock<std::mutex> ul(_alert_m);
while(!_alert_loop_should_stop) {
_alert_cv.wait(ul, [&]() {
return _alert_pending || _alert_loop_should_stop;
})
if(_alert_pending) {
_alert_pending = false;
ul.unlock();
session.pop_alerts(...);
...
ul.lock();
}
}

相关内容

最新更新