Как правильно использовать set_alert_notify для пробуждения основного потока?

Я пытаюсь написать свою собственную торрент-программу на основе libtorrent rasterbar, и у меня возникают проблемы с корректной работой механизма оповещения. 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)); что уменьшает количество циклов в секунду, сохраняя достаточно низкую задержку.

Но это действительно более обходной путь, чем решение, и я продолжаю думать, что должен быть правильный способ справиться с этим.

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]