当deadline_timer等待时,使用io_service :: post(boost)

时间:2016-08-05 15:18:47

标签: c++ boost timer boost-asio deadlines

使用deadline_timer和io_service :: post时遇到问题如下:

#include "boost/asio.hpp"
#include "boost/thread.hpp"
int main()
{
    boost::asio::io_service io_service;

    boost::asio::deadline_timer timer1(io_service);
    boost::asio::deadline_timer timer2(io_service);

    timer1.expires_from_now(boost::posix_time::seconds(1));
    timer1.async_wait([](const boost::system::error_code& error) {
        boost::this_thread::sleep(boost::posix_time::seconds(5));
        printf("1 ");
    });

    timer2.expires_from_now(boost::posix_time::seconds(2));
    timer2.async_wait([](const boost::system::error_code& error) {
        printf("2 ");
    });

    boost::thread t([&io_service]() {
        boost::this_thread::sleep(boost::posix_time::seconds(5));
        io_service.post([]() {
            printf("3 ");
        });
        io_service.post([]() {
            printf("4 ");
        });
    });

    io_service.run();
    t.join();
    getchar();

    return 0;
}

我认为结果是“1 2 3 4”但结果是“1 3 4 2”。任何人都可以告诉我如何使用boost库来执行timer2(打印“2”)的回调作为结果“1 2 3 4”(并且不要改变timer1和timer2的过期时间)。

非常感谢!

4 个答案:

答案 0 :(得分:0)

这实际上是一个非常复杂的例子。

io_service将在主线程上运行。这是操作顺序

主线程:

  • 请求定时器在T0 + 1
  • 请求计时器在T0 + 2
  • 产生线程
  • 执行所有待处理的io(io_service.run()

辅助主题:

  • 睡5秒
  • 请求计时器
  • 请求计时器

首先,在调用io_service之前,io_service.run()不执行任何操作。

调用io_service.run()后,将安排将来1秒的计时器。当该计时器触发时,它首先会在打印1之前休眠5秒钟。

当该线程正在执行时,辅助线程也会出现,并且会休眠5秒钟。在timer1的处理程序中执行的计时器完成之前,将设置并调度此线程。由于这两个线程都会休眠5秒钟,因此“2”和“3”会立即发布到io_service

现在事情变得有点棘手了。 timer2的超时似乎现在应该已经过期(将来至少5秒),但在处理io_service时有两个命令直接发布到timer1 }}

似乎在实现细节中,boost优先于截止时间计时器操作直接发布的操作。

答案 1 :(得分:0)

第一个计时器到期阻止io(主)线程运行,同时另一个线程将一些项目发布到asio工作队列,一旦计时器1的回调完成,第二个计时器到期就会导致回调排队但没有执行。从“3”开始已经排队的“4”(当“1”阻塞主线程时),它们先于“2”

asio的意思是不阻止。通过在第一个定时器回调(睡眠)中放置长时间运行的工作,您已经阻止了io线程及时运行。您应该将该工作卸载到专用线程中,并将其完成发布回asio。

答案 2 :(得分:0)

let myButton = NSButton() myButton.title = "OK" myButton.bezelStyle = .RoundedBezelStyle let titleBarView = window!.standardWindowButton(.CloseButton)!.superview! titleBarView.addSubview(myButton) myButton.translatesAutoresizingMaskIntoConstraints = false titleBarView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[myButton]-2-|", options: [], metrics: nil, views: ["myButton": myButton])) titleBarView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-1-[myButton]-3-|", options: [], metrics: nil, views: ["myButton": myButton])) 不保证处理程序的调用顺序。从理论上讲,可以按任何顺序调用处理程序,其中一些排列很不可能。

如果需要以非常特定的顺序调用处理程序,那么请考虑以强制执行所需处理程序链的方式重构异步调用链。此外,可能会发现有必要使用strand提供的保证顺序的处理程序调用。考虑不要通过脆弱的睡眠和计时器来控制复杂的处理程序调用。

答案 3 :(得分:0)

你的第一个问题是你试图阻止处理程序内部:

timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
    boost::this_thread::sleep(boost::posix_time::seconds(5)); // <--- HERE
    printf("1 ");
});

上述代码中发生的情况是,在timer1等待一秒后,它会将回调发布到io_service。在io_service::run函数内部执行此回调,但此执行在主线程内部发生,因此它会暂停五秒钟,从而阻止timer2将其处理程序发布到io_service。它一直执行到程序执行的第六秒(6 = 5 + 1)。

同时线程t被执行,在程序执行的第五秒,它将这两个printf(&#34; 3&#34;)和printf(&#34; 4&#34;)发布到{{ 1}}。

io_service

一旦来自boost::thread t([&io_service]() { boost::this_thread::sleep(boost::posix_time::seconds(5)); io_service.post([]() { printf("3 "); }); io_service.post([]() { printf("4 "); }); }); 的处理程序取消阻止,它就允许timer1将其处理程序发布到timer2。这又发生在程序执行的第六秒,也就是说,io_serviceprintf("3")已经发布了!

总而言之,我相信你所寻找的是:

printf("4")