C++ 在截止时间计时器等待时使用io_服务::post(boost)

C++ 在截止时间计时器等待时使用io_服务::post(boost),c++,boost,timer,boost-asio,deadlines,C++,Boost,Timer,Boost Asio,Deadlines,我在使用截止期计时器和io_服务时遇到问题::发布如下: #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); time

我在使用截止期计时器和io_服务时遇到问题::发布如下:

#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;
}
我认为结果是“1234”,但结果是“12342”。任何人都可以告诉我如何使用boost库在“1 2 3 4”结果之前执行timer2回调(打印“2”)(并且不要更改timer1和timer2的过期时间)


非常感谢

这实际上是一个相当复杂的例子


io\u服务将在主线程上运行。以下是操作顺序

主线程:

  • T0+1处的请求计时器
  • T0+2处的请求计时器
  • 繁殖线程
  • 执行所有挂起的io(
    io\u service.run()
次线程:

  • 睡眠5秒钟
  • 请求计时器
  • 请求计时器
首先,在调用
io\u服务.run()
之前,在
io\u服务中不会执行任何操作

一旦调用了
io\u service.run()
,将安排未来1秒的计时器。当计时器启动时,它首先休眠5秒,然后再打印1

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

boost::thread t([&io_service]() {
    boost::this_thread::sleep(boost::posix_time::seconds(5));
    io_service.post([]() {
        printf("3 ");
    });
    io_service.post([]() {
        printf("4 ");
    });
});
现在事情变得有点棘手了。似乎
timer2
的超时现在应该已经过期(未来至少5秒),但在处理
timer1
时,有两条命令直接发布到
io\u服务


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

第一个计时器过期会阻止io(主)线程运行,同时,一旦计时器1的回调完成,另一个线程会向asio工作队列发布两个项目,处理第二个计时器过期,这将导致回调排队但不执行。因为“3”和“4”已经排队(而“1”阻塞了主线程),所以它们在“2”之前


asio的要点是不要阻塞。通过将长时间运行的工作放在第一次回调(睡眠)中,可以防止io线程及时运行。您应该将该工作卸载到一个专用线程中,并将其完成后返回到asio。

io_服务
不保证处理程序的调用顺序。从理论上讲,处理程序可以按任何顺序调用,某些排列方式不太可能


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

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

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
的处理程序解除阻止,它允许
timer2
将其处理程序发布到
io\u服务
。在程序执行的第六秒,也就是说,一旦发布了
printf(“3”)
printf(“4”)
,就会再次发生这种情况

总而言之,我相信你想要的是:

#include "boost/asio.hpp"
#include "boost/thread.hpp"

int main()
{
    boost::asio::io_service io_service;
    boost::optional<boost::asio::io_service::work> work(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) {
        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, &work]() {
        boost::this_thread::sleep(boost::posix_time::seconds(5));
        io_service.post([]() {
            printf("3 ");
        });
        io_service.post([&work]() {
            printf("4 ");
            work = boost::none;
        });
    });

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

    return 0;
}
#包括“boost/asio.hpp”
#包括“boost/thread.hpp”
int main()
{
boost::asio::io_服务io_服务;
boost::可选工作(io_服务);
boost::asio::截止时间计时器1(io\u服务);
boost::asio::deadline\u timer2(io\u服务);
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code&error){
printf(“1”);
});
timer2.expires_from_now(boost::posix_time::seconds(2));
timer2.async\u wait([](常量boost::system::error\u代码和错误){
printf(“2”);
});
boost::线程t([&io_服务和工作](){
boost::this_线程::sleep(boost::posix_时间::秒(5));
io_service.post([](){
printf(“3”);
});
io_service.post([&工作](){
printf(“4”);
工作=提升::无;
});
});
io_service.run();
t、 join();
返回0;
}
⚠ 在不重新设计调用链或修改计时器的情况下,可以获得一个非常脆弱的解决方案,该解决方案严重依赖于实现细节⚠