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

时间:2017-07-09 20:13:02

标签: c++ multithreading c++11 libtorrent-rasterbar

我正在尝试编写基于libtorrent rasterbar的自己的torrent程序,并且我在使警报机制正常工作时遇到问题。 Libtorrent提供功能

    self::$rCh = curl_init();
    curl_setopt( self::$rCh, CURLOPT_RETURNTRANSFER, true );
    curl_setopt( self::$rCh, CURLOPT_TIMEOUT, 30 );
    curl_setopt( self::$rCh, CURLOPT_CONNECTTIMEOUT, self::iTimeout );
    curl_setopt( self::$rCh, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; 
Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13' );
    curl_setopt( self::$rCh, CURLOPT_SSL_VERIFYHOST, 0 );
    curl_setopt( self::$rCh, CURLOPT_SSL_VERIFYPEER, 0 );
    curl_setopt( self::$rCh, CURLOPT_POST, 0 ); 
    curl_setopt( self::$rCh, CURLOPT_PROXY, 'a123:b123:123::1' );
    curl_setopt( self::$rCh, CURLOPT_PROXYPORT, 12345 );
    $sPage = curl_exec( self::$rCh );

应该是

  

该函数的目的是客户端唤醒其主线程,使用pop_alerts()轮询更多警报。如果notify函数无法执行此操作,则在调用pop_alerts之前不会再次调用它。

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

void set_alert_notify (boost::function<void()> const& fun);
然而,有一个竞争条件。如果 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);,这足以减少每秒的循环次数,同时保持足够低的延迟。

但实际上解决方案确实更具解决方法,我一直认为必须有适当的方法来解决这个问题。

1 个答案:

答案 0 :(得分:0)

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

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();
    }
}