2016-08-05 55 views
2

我有一个问题,同时使用deadline_timer和io_service对象::交如下:使用io_service对象::交(增压)时deadline_timer等待

#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库(以及不更改timer1和timer2的过期时间)之前执行timer2(print“2”)的回调,结果为“1 2 3 4”。

非常感谢!

回答

0

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

io_service将在主线程上运行。下面是操作的顺序

主线程:在在T0 + 2

  • 菌种螺纹
  • 执行所有未决IO T0 + 1
  • 请求定时器

    • 请求定时器(io_service.run()

    次要线程:

    • 睡眠5秒
    • 请求定时器
    • 请求定时器

    首先,什么都不会在io_service直到io_service.run()执行被调用。

    一旦调用了io_service.run(),计划将来1秒的计时器。当该定时器触发时,它首先在打印1之前睡5秒钟。

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

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

    看来,在实施细节中,boost会优先于直接在截止日期计时器操作上发布操作。

  • 0

    第一次计时器到期会阻止io(主)线程运行,同时另一个线程会向asio工作队列发布几个项目,一旦计时器1的回调完成,第二个计时器到期将被处理,导致回调被排队但未被执行。因为已经排队的“3”&“4”(当“1”阻塞主线程时),它们超前于“2”

    asio的要点是不阻塞。通过在第一次定时器回调(睡眠)中放置长时间运行的工作,可以防止io线程及时运行。你应该将这项工作转移到一个专用线程中,并将其完成回传给asio。

    0

    io_service不保证处理程序的调用顺序。理论上,可以以任何顺序调用处理程序,某些排列是不太可能的。

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

    +0

    ** **⚠没有返工调用链或修改的计时器,它在很大程度上依赖于实施细节极其脆弱的解决方案可在[这里](http://coliru.stacked-crooked.com/a/0524433bb0bdcf71)**⚠** –

    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(“3”)和printf(“4”)发送到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_service。这又发生在程序执行的第六秒,也就是说,一旦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; 
    }