c – boost :: asio :: deadline_timer没有醒来(压力情景)

我正在使用deadline_timer作为异步事件,并且我遇到这样的情况,经过一段时间后,等待事件的线程似乎永远不会被唤醒(尽管有更多调用cancel()).我已经能够使用我在下面粘贴的一些示例代码重现这一点;它并不完全一致,但我已经看到了我认为与我遇到的问题相同的问题.

boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);

int num_events = 0;
auto waiter = [&timer, &num_events](boost::asio::yield_context context) {
  while (true) {
    std::cout << "waiting on event" << std::endl;
    boost::system::error_code e;
    timer.async_wait(context[e]);
    std::cout << "got event (" << e << ")" << std::endl;
    ++num_events;
  }
};

boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));

for (auto i = 0; i < 500000; ++i) {
  timer.cancel();
  std::cout << i << std::endl;
}

我在这里做的事情是不受支持的,无意中遇到了一些竞争条件?来自wait()的错误代码从来看起来并不麻烦(即使是在最后一次它再次出现之前就已经被唤醒了).编辑:我也注意到3个不同平台(Windows,Mac和Linux)上的原始错误,但我一直用于重现的上述测试已经在Windows上.

最佳答案 deadline_timer对象不是线程安全的.

你从另一个线程取消它而不是发布async_wait的线程.这意味着电话可以比赛.

我不确定这样可以完全抑制样本中的回调.在我看来程序应该/只是/退出因为500000的紧密循环快速完成(执行许多永远不会被处理的冗余取消,因为协程将例如甚至没有发布新的async_wait).

所以,也许你的意思是“为什么我不能获得500000个活动”.

UPDATE

在评论之后,这是一个微不足道的转变,展示了如何在演员中调用计时器上的成员.注意:这关键取决于io_service仅从单个线程运行的想法!

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <iostream>

using boost::thread;
using boost::asio::io_service;

int main() {
    boost::asio::io_service     io_service;

    boost::asio::deadline_timer timer(io_service);
    timer.expires_at(boost::posix_time::pos_infin);

    boost::atomic_bool shutdown(false);

    int num_events = 0;
    auto waiter = [&timer, &num_events, &shutdown](boost::asio::yield_context context) {
        while (!shutdown) {
            std::cout << "waiting on event" << std::endl;

            boost::system::error_code e;
            timer.async_wait(context[e]);

            std::cout << "got event (" << e.message() << ")" << std::endl;
            ++num_events;
        }
    };

    boost::asio::spawn(io_service, std::move(waiter));
    boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));

    for (auto i = 0; i < 5000; ++i) {
        io_service.post([&timer, i]{ 
                std::cout << i << std::endl;
                timer.cancel(); 
            });
    }

    io_service.post([&]{ 
            shutdown = true;
            timer.cancel();
        });

    thread.join();

    std::cout << "Check: " << num_events << " events counted\n";
}

此外,您似乎只想发出后台任务信号.如您所述,您可以简化程序,如:

见它Live On Coliru

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/make_shared.hpp>
#include <iostream>

using boost::thread;
using boost::asio::io_service;

int main() {
    io_service svc;
    int num_events = 0;

    auto work = boost::make_shared<io_service::work>(svc); // keep svc running
    boost::thread thread(boost::bind(&io_service::run, &svc));

    for (auto i = 0; i < 500000; ++i) {
        svc.post([&num_events,i]{
                std::cout << "got event (" << i << ")" << std::endl;
                ++num_events;
                });
    }

    work.reset();
    thread.join();

    std::cout << "Check: " << num_events << " events counted\n";
}

这会打印所有500000个事件:

got event (0)
got event (1)
got event (3)
...
got event (499998)
got event (499999)
Check: 500000 events counted
点赞