2013-11-15 69 views
22

當在C++中編寫一個以超時爲參數的函數時,我應該使用什麼類型的超時參數本身?在C++中用於超時變量的類型是什麼?

這樣的功能的一個例子可能是:

void my_function(bool work_really_hard, timeout_type timeout) 
{ 
// Do stuff, until timeout is reached. 
} 

我曾經想過用std::chrono::secondstimeout_type,但不允許使用的亞秒級領域中的任何超時。

當使用std::chrono::nanoseconds代替時,指定例如10分鐘是麻煩的。

任何方式來以合理的方式解決這個問題,同時保持函數簽名和調用整潔和簡單?

+0

使用'wait_until'或'sleep_until'元? IOW,使用截止時間而不是超時 – sehe

+0

@sehe超時遵從的內部與這個問題無關(我沒有任何控制權)。我只關心函數簽名中的超時類型。 – JohnCand

+0

毫秒怎麼樣?以毫秒爲單位指定超時是_kinda_標準。另外 - 「std :: chrono」類型以比率表示,因此您可以使用非整數值。 – Tibor

回答

24

使用的std ::時辰::納秒相反,它是麻煩 指定,比如說10分鐘。

其實,這並不能使它在最麻煩的:

#include <chrono> 
#include <iostream> 

void my_function(bool work_really_hard, std::chrono::nanoseconds timeout) 
{ 
    std::cout << timeout.count() << '\n'; 
} 

int 
main() 
{ 
    my_function(true, std::chrono::minutes(10)); 
} 

輸出:

600000000000 

你就會有麻煩nanoseconds的唯一情況是,如果你想傳遞的東西不會完全轉換爲nanoseconds,如picosecondsduration<long, ratio<1, 3>>(1/3秒單位)。

更新

我打算這個答案是,我覺得這是一個很好的答案(由sehe)已經接受的答案的其他信息。 sehe推薦了一個模板化的解決方案,我也認爲這很好。

如果你想接受任何std::chrono::duration,甚至是一個你可能不得不truncate or round,然後用sehe的刪除,答案會是要走的路:

template <typename Rep, typename Period> 
void my_function(bool work_really_hard, std::chrono::duration<Rep, Period> timeout) 
{ 
    // Do stuff, until timeout is reached. 
    std::this_thread::sleep_for(timeout); 
} 

如果由於某種原因你不想處理模板和/或您滿意於讓您的客戶只需指定可正確轉換爲std::chrono:nanoseconds的單元,然後使用std::chrono:nanoseconds就像我上面顯示的那樣也是完全可以接受的。

所有的std::chrono「預定義」單位:

hours 
minutes 
seconds 
milliseconds 
microseconds 
nanoseconds 

是隱式轉換爲nanoseconds,不會涉及任何截斷或舍入誤差。只要將其保持在兩條明亮的白線內(將您的車保持在您自己的車道中的含義模糊),就不會發生溢流。只要持續時間在+/- 292年以內,您就不必擔心這些預定義單位的溢出。

諸如std::this_thread::sleep_for這樣的標準定義的函數被模板化,正如其希望能夠與可想象的每個chrono:duration(例如浮點飛秒的1/3)互操作的原因一樣。由API設計人員決定他們是否需要在自己的API中具有很大的靈活性。

如果我現在設法弄糊塗你而不是澄清,不要太擔心。如果您選擇使用nanoseconds,則事情可能會正常工作,不會發生截斷或四捨五入錯誤,或者客戶端將收到編譯時錯誤。將會有沒有運行時錯誤。

void my_function(bool work_really_hard, std::chrono::nanoseconds timeout) 
{ 
    std::cout << timeout.count() << '\n'; 
} 

int 
main() 
{ 
    using namespace std; 
    using namespace std::chrono; 
    typedef duration<double, pico> picoseconds; 
    my_function(true, picoseconds(100000.25)); 
} 

test.cpp:15:9: error: no matching function for call to 'my_function' 
     my_function(true, picoseconds(100000.25)); 
     ^~~~~~~~~~~ 
test.cpp:4:10: note: candidate function not viable: no known conversion from 'duration<double, ratio<[...], 1000000000000>>' to 
     'duration<long long, ratio<[...], 1000000000>>' for 2nd argument 
    void my_function(bool work_really_hard, std::chrono::nanoseconds timeout) 
     ^
1 error generated. 

如果客戶得到一個編譯時錯誤,他可以隨時使用duration_cast解決它:

my_function(true, duration_cast<nanoseconds>(picoseconds(100000.25))); // Ok 

欲知詳情,請訪問:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm

對此答案頂部的原始代碼進行更新。在C++ 1Y,我們希望意味着C++ 14:

using namespace std::literals; 
my_function(true, 10min); // also ok, is equal to 600000000000 nanoseconds 

問:你會推薦爲 「無窮大」 的超時什麼(即不超時)

我會首先嚐試使用沒有超時的API,並暗示「不超時」。例如condition_variable::wait。如果我可以控制API,那麼我會在沒有超時的情況下創建這樣的簽名。

做不到這一點,我會創造出一系列「大」 chrono::durations

typedef std::chrono::duration 
< 
    std::int32_t, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>> 
> days; 

typedef std::chrono::duration 
< 
    std::int32_t, std::ratio_multiply<days::period, std::ratio<7>> 
> weeks; 

typedef std::chrono::duration 
< 
    std::int32_t, std::ratio_multiply<days::period, std::ratio<146097, 400>> 
> years; 

typedef std::chrono::duration 
< 
    std::int32_t, std::ratio_divide<years::period, std::ratio<12>> 
> months; 

然後,我會用我的電話,這些大持續時間之一,例如:

std::this_thread::sleep_for(years(3)); 

我不會嘗試最大限度地發揮作用(例如,您可能會破壞操作系統所做的基本假設)。只是隨意挑選一些可笑的東西(比如3年)。這將會吸引您的代碼審查人員的注意力,並可能引發信息量大的對話。 :-)

現在提供了視頻:https://www.youtube.com/watch?v=P32hvk8b13M :-)

+0

+1這應該是被接受的答案。這讓我感覺很尷尬:) – sehe

+0

我會接受這個答案並承認我不會因爲沒有嘗試如此明顯的事情而感到尷尬。 'std :: chrono :: duration'實際上[具有以其他持續時間類型作爲參數的構造函數](http://en.cppreference.com/w/cpp/chrono/duration/duration)。 – JohnCand

+0

我希望我可以多次提升您的答案,您的更新真的很感激。一個小小的後續問題:如果我不想使用0,那麼你會推薦什麼作爲「無窮大」的超時(即不超時),同時要記住可能的有符號/無符號轉換和溢出底層類型的問題? – JohnCand

1

對超時類型使用模板參數,並期望使用std::chrono類型之一或具有類似接口的類型;這將允許你通過任何單位的時間。

template<typename T> 
void wait_a_while(const T& duration) 
{ 
    std::this_thread::sleep(duration); 
} 

wait_a_while(boost::posix_time::seconds(5)); 
wait_a_while(std::chrono::milliseconds(30)); 
+0

只是一個人擡頭,因爲你的答案和我所做的差不多。尋找清晰的片刻:) – sehe

相關問題