2016-08-05 60 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; 
    }