2014-04-10 69 views
4

假設我有以下代碼:提升線程和try_join_for給出不同的輸出每次

#include <boost/chrono.hpp> 
#include <boost/thread.hpp> 

#include <iostream> 

int main() 
{ 
    boost::thread thd([]{ std::cout << "str \n"; }); 

    boost::this_thread::sleep_for(boost::chrono::seconds(3)); 

    if (thd.try_join_for(boost::chrono::nanoseconds(1))) 
    { 
    std::cout << "Finished \n"; 
    } 
    else 
    { 
    std::cout << "Running \n"; 
    } 
} 

MSVC 12.0和提升1.55每次都帶給我不同的輸出,當我啓動該程序。例如,

str 
Finished 

str 
Finished 

str 
Running 

當我將boost :: chrono :: nanoseconds更改爲boost :: chrono :: microseconds時,輸出看起來和預期的一樣。

爲什麼?我究竟做錯了什麼?它是一個提升庫中的錯誤嗎?是否有一張關於提升錯誤跟蹤器的機票?

在此先感謝。

回答

3

你的程序只是有一場比賽,很可能是因爲1納秒非常短的事實。

try_join_for是通過調用try_join_until實施,這將嘗試加入一個函數,直到某個時間點已經達到:

// I stripped some unrelated template stuff from the code 
// to make it more readable 

bool try_join_for(const chrono::duration& rel_time) 
{ 
    return try_join_until(chrono::steady_clock::now() + rel_time); 
} 

bool try_join_until(const chrono::time_point& t) 
{ 
    system_clock::time_point  s_now = system_clock::now(); 
    bool joined= false; 
    do { 
    Clock::duration d = ceil<nanoseconds>(t-Clock::now()); 
    if (d <= Clock::duration::zero()) 
     return false; // in case the Clock::time_point t is already reached 
    // only here we attempt to join for the first time: 
    joined = try_join_until(s_now + d); 
    } while (! joined); 
    return true; 
} 

現在的問題是,try_join_until將檢查是否之前請求time_point已經達到嘗試加入。如您所見,它需要執行另外兩個調用clock::now()以及一些計算來比較獲得的值與用戶給出的截止日期。這可能會或可能不會完成時鐘跳出超過您的1納秒的最後期限,導致輸出的不可預測性。

請注意,像這樣的一般時序相關代碼是脆弱的。即使超時時間爲毫秒級,如果在執行過程中出現壞點並且CPU負載過重,則可能會在極少數情況下錯過最後期限。因此,請務必小心謹慎地選擇您的最後期限,並且絕對不要假設在所有可能的情況下截止日期都足夠大。

+1

不錯的答案:我想知道'比賽',因爲在加入嘗試之前有三秒的延遲。但是這個種族不在另一個線程中,而是在'try_join_until()'中的計時器。 –

0

剛打電話.join()有什麼問題?如果你堅持,你可以檢查你加入之前:

#include <boost/chrono.hpp> 
#include <boost/thread.hpp> 

#include <iostream> 

int main() 
{ 
    boost::thread thd([]{ std::cout << "str\n"; }); 
    boost::this_thread::sleep_for(boost::chrono::seconds(3)); 

    if (thd.joinable()) 
     thd.join(); 
} 

需要注意的是,如果你無法加入程序退出前一個線程的行爲無論如何不確定的。使用

  • 期貨,
  • 條件變量或
  • 信號燈

信號作業完成,如果這就是你要監控。