概覽
c++新標准提供了新的線程庫,最近在寫測試代碼的時候需要讓當前線程休眠,之前直接調用windows提供的Sleep()就好了,新標准中可以使用std::this_thread::sleep_for()或者std::this_thread::sleep_until()
來實現休眠。其中涉及到了std::chrono::duration和std::chrono::time_point。本篇只總結std::chrono::duration,std::chrono::time_point會再寫一篇總結。
std::chrono::duration
描述
std::chrono::duration定義在
cppreference上的原話如下:
Class template std::chrono::duration represents a time interval.
It consists of a count of ticks of type Rep and a tick period, where the tick period is a compile-time rational constant representing the number of seconds from one tick to the next.
The only data stored in a duration is a tick count of type Rep. If Rep is floating point, then the duration can represent fractions of ticks. Period is included as part of the duration's type, and is only used when converting between different durations.
Rep
參數代表了可以傳入的時間單位的類型,可以為float, int, int64等等,如果為float表示可以傳入時間單位的一部分,比如傳入1.2表示1.2倍個時間單位。
Period
參數代表了時間單位,可以為微秒,毫秒,秒,分鍾,小時等(或者其它自定義的單位,類型為std::ratio)。
注:
- 上文中的tick可以理解為周期,或時間單位。
- the number of seconds 表示是周期值基於秒來計算的。
類定義
std::chrono::duration是一個模板類,關鍵代碼摘錄如下(格式有調整):
- template<class _Rep, class _Period>
- class duration {
- public:
- typedef duration<_Rep, _Period> _Myt;
- typedef _Rep rep;
- typedef _Period period;
- // constructor, save param to _MyRep, used by count() member function.
- template<class _Rep2,
- class = typename enable_if<is_convertible<_Rep2, _Rep>::value
- && (treat_as_floating_point<_Rep>::value || !treat_as_floating_point<_Rep2>::value),
- void>::type>
- constexpr explicit duration(const _Rep2& _Val)
- : _MyRep(static_cast<_Rep>(_Val))
- {
- }
- constexpr _Rep count() const { return (_MyRep); }
- };
- // convert duration from one unit to another.
- template<class _To, class _Rep, class _Period> inline
- constexpr typename enable_if<_Is_duration<_To>::value, _To>::type
- duration_cast(const duration<_Rep, _Period>& _Dur)
- {
- typedef ratio_divide<_Period, typename _To::period> _CF;
- typedef typename _To::rep _ToRep;
- typedef typename common_type<_ToRep, _Rep, intmax_t>::type _CR;
- return (_CF::num == 1 && _CF::den == 1
- ? static_cast<_To>(static_cast<_ToRep>(_Dur.count()))
- : _CF::num != 1 && _CF::den == 1
- ? static_cast<_To>(static_cast<_ToRep>(
- static_cast<_CR>(
- _Dur.count()) * static_cast<_CR>(_CF::num)))
- : _CF::num == 1 && _CF::den != 1
- ? static_cast<_To>(static_cast<_ToRep>(
- static_cast<_CR>(_Dur.count())
- / static_cast<_CR>(_CF::den)))
- : static_cast<_To>(static_cast<_ToRep>(
- static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num)
- / static_cast<_CR>(_CF::den))));
- }
duration_cast()分析
函數duration_cast()
提供了在不同的時間單位之間進行轉換的功能。
duration_cast()
主要分為兩部分:
-
通過
ratio_divide
定義了從一個ratio轉換到另外一個ratio的轉換比例。
比如1/10
到2/5
的轉換比例是1/4
((1/10/(2/5)) = 1/4),也就是說一個1/10
相當於1/4
個2/5
。
對應到代碼里就是_CF::num = 1, _CF::den = 4
. -
根據轉換比例把n個單位的原數據轉換到目標數據(return語句)
return
語句寫的這么復雜是為了效率,避免不必要的乘除法,當分子是1的時候沒必要乘,當分母是1的時候沒必要除。
簡化一下(去掉了強制類型轉換)就是:
return _Dur.count() * (_CF::num / _CF::den);
通俗點講:如果A
到B
的轉換比例是num/den
,那么1
個A
可以轉換為num/den
個B
, n
個A
可以轉換為 n * (num/den)
個B
。
注:vs自帶的源碼真心不易讀,推薦參考boost源碼。
預定義的duration
vs為了寫代碼方便,預定義了幾個常用的時間單位,摘錄如下:
- typedef duration<long long, nano> nanoseconds; // 納秒
- typedef duration<long long, micro> microseconds; // 微秒
- typedef duration<long long, milli> milliseconds; // 毫秒
- typedef duration<long long> seconds; // 秒
- typedef duration<int, ratio<60> > minutes; // 分鍾
- typedef duration<int, ratio<3600> > hours; // 小時
根據以上定義我們可以發現std::chrono::microseconds
定義中的Rep
的類型是long long
,Period
類型是milli
。
注:因為
std::chrono::microseconds
定義中的Rep
的類型是long long
, 我們不能通過如下方法來休眠100.5毫秒std::this_thread::sleep_for(std::chrono::microseconds(100.5));
,類型不匹配,會報編譯錯誤。如果想休眠100.5毫秒,我們可以這么寫:
std::this_thread::sleep_for(std::chrono::duration<float, std::milli>(100.5f));
示例代碼
例1:分鍾轉換為毫秒
- int main()
- {
- std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::minutes(3));
- std::cout << "3 minutes equals to " << ms.count() << " milliseconds\n";
- std::cin.get();
- }
例2. 自定義單位轉換
- typedef std::chrono::duration<float, std::ratio<3, 1> > three_seconds;
- typedef std::chrono::duration<float, std::ratio<1, 10> > one_tenth_seconds;
- int main()
- {
- three_seconds s = std::chrono::duration_cast<three_seconds>(one_tenth_seconds(3));
- std::cout << "3 [1/10 seconds] equal to " << s.count() << " [3 seconds]\n";
- std::cin.get();
- }
例3. 休眠100毫秒
- int main()
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- // or
- std::this_thread::sleep_for(std::chrono::duration<long long, std::milli>(100));
- // or
- // typedef ratio<1, 1000> milli;
- std::this_thread::sleep_for(std::chrono::duration<long long, std::ratio<1, 1000> >(100));
- }
參考資料
- VS源碼
- cppreference