[原]C++新標准之std::chrono::duration


概覽

c++新標准提供了新的線程庫,最近在寫測試代碼的時候需要讓當前線程休眠,之前直接調用windows提供的Sleep()就好了,新標准中可以使用std::this_thread::sleep_for()或者std::this_thread::sleep_until()
來實現休眠。其中涉及到了std::chrono::durationstd::chrono::time_point。本篇只總結std::chrono::durationstd::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)。

注:

  1. 上文中的tick可以理解為周期,或時間單位。
  2. the number of seconds 表示是周期值基於秒來計算的。

類定義

std::chrono::duration是一個模板類,關鍵代碼摘錄如下(格式有調整):

  1. template<class _Rep, class _Period> 
  2. class duration { 
  3. public
  4. typedef duration<_Rep, _Period> _Myt; 
  5. typedef _Rep rep; 
  6. typedef _Period period; 
  7.  
  8. // constructor, save param to _MyRep, used by count() member function. 
  9. template<class _Rep2, 
  10. class = typename enable_if<is_convertible<_Rep2, _Rep>::value 
  11. && (treat_as_floating_point<_Rep>::value || !treat_as_floating_point<_Rep2>::value), 
  12. void>::type> 
  13. constexpr explicit duration(const _Rep2& _Val) 
  14. : _MyRep(static_cast<_Rep>(_Val)) 
  15.  
  16. constexpr _Rep count() const { return (_MyRep); } 
  17. }; 
  18.  
  19. // convert duration from one unit to another. 
  20. template<class _To, class _Rep, class _Period> inline 
  21. constexpr typename enable_if<_Is_duration<_To>::value, _To>::type 
  22. duration_cast(const duration<_Rep, _Period>& _Dur) 
  23. typedef ratio_divide<_Period, typename _To::period> _CF; 
  24.  
  25. typedef typename _To::rep _ToRep; 
  26. typedef typename common_type<_ToRep, _Rep, intmax_t>::type _CR; 
  27.  
  28. #pragma warning(push) 
  29. #pragma warning(disable: 6326) // Potential comparison of a constant with another constant. 
  30. return (_CF::num == 1 && _CF::den == 1 
  31. ? static_cast<_To>(static_cast<_ToRep>(_Dur.count())) 
  32. : _CF::num != 1 && _CF::den == 1 
  33. ? static_cast<_To>(static_cast<_ToRep>( 
  34. static_cast<_CR>( 
  35. _Dur.count()) * static_cast<_CR>(_CF::num))) 
  36. : _CF::num == 1 && _CF::den != 1 
  37. ? static_cast<_To>(static_cast<_ToRep>( 
  38. static_cast<_CR>(_Dur.count()) 
  39. / static_cast<_CR>(_CF::den))) 
  40. : static_cast<_To>(static_cast<_ToRep>( 
  41. static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num) 
  42. / static_cast<_CR>(_CF::den)))); 
  43. #pragma warning(pop) 

duration_cast()分析

函數duration_cast()提供了在不同的時間單位之間進行轉換的功能。

duration_cast()主要分為兩部分:

  • 通過ratio_divide定義了從一個ratio轉換到另外一個ratio的轉換比例。
    比如1/102/5的轉換比例是1/4 ((1/10/(2/5)) = 1/4),也就是說一個1/10相當於1/42/5
    對應到代碼里就是_CF::num = 1, _CF::den = 4.

  • 根據轉換比例把n個單位的原數據轉換到目標數據(return語句)
    return語句寫的這么復雜是為了效率,避免不必要的乘除法,當分子是1的時候沒必要乘,當分母是1的時候沒必要除。
    簡化一下(去掉了強制類型轉換)就是:
    return _Dur.count() * (_CF::num / _CF::den);

通俗點講:如果AB的轉換比例是num/den,那么1A可以轉換為num/denB, nA可以轉換為 n * (num/den)B

注:vs自帶的源碼真心不易讀,推薦參考boost源碼。

預定義的duration

vs為了寫代碼方便,預定義了幾個常用的時間單位,摘錄如下:

  1. typedef duration<long long, nano> nanoseconds; // 納秒 
  2. typedef duration<long long, micro> microseconds; // 微秒 
  3. typedef duration<long long, milli> milliseconds; // 毫秒 
  4. typedef duration<long long> seconds; // 秒 
  5. typedef duration<int, ratio<60> > minutes; // 分鍾 
  6. typedef duration<int, ratio<3600> > hours; // 小時 

根據以上定義我們可以發現std::chrono::microseconds定義中的Rep的類型是long longPeriod類型是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:分鍾轉換為毫秒

  1. #include <iostream> 
  2. #include <chrono> 
  3. int main() 
  4. std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::minutes(3)); 
  5. std::cout << "3 minutes equals to " << ms.count() << " milliseconds\n"
  6. std::cin.get(); 

例2. 自定義單位轉換

  1. #include <iostream> 
  2. #include <chrono> 
  3.  
  4. typedef std::chrono::duration<float, std::ratio<3, 1> > three_seconds; 
  5. typedef std::chrono::duration<float, std::ratio<1, 10> > one_tenth_seconds; 
  6.  
  7. int main() 
  8. three_seconds s = std::chrono::duration_cast<three_seconds>(one_tenth_seconds(3)); 
  9. std::cout << "3 [1/10 seconds] equal to " << s.count() << " [3 seconds]\n"
  10. std::cin.get(); 

例3. 休眠100毫秒

  1. #include <thread> 
  2. #include <chrono> 
  3. int main() 
  4. std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
  5. // or 
  6. std::this_thread::sleep_for(std::chrono::duration<long long, std::milli>(100)); 
  7. // or  
  8. // typedef ratio<1, 1000> milli; 
  9. std::this_thread::sleep_for(std::chrono::duration<long long, std::ratio<1, 1000> >(100)); 

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM