std::chrono是C++11引入的日期時間處理庫,其中包含3種時鍾:system_clock,steady_clock,high_resolution_clock。近來需要使用高精度時間,很自然想到使用high_resolution_clock,然而使用后發現並非預期的得到自1970/1/1零點之后的計數,而是一個小得多的數字。那么這三種時鍾有什么區別,用在什么情況下,我們來一探究竟。
問題
auto tp = std::chrono::high_resolution_clock::now();
std::cout << tp.time_since_epoch().count() << std::endl;
上述代碼輸出一個比較小的數字,high_resolution_clock的精度是納秒,不可能是這么小的數字。
三種時鍾的區別
所謂時鍾,是指從一個時點開始,按照某個刻度的一個計數。如下代碼摘自VC2017。
- system_clock
struct system_clock
{ // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime
typedef long long rep;
typedef ratio_multiply<ratio<_XTIME_NSECS_PER_TICK, 1>, nano> period;
typedef chrono::duration<rep, period> duration;
typedef chrono::time_point<system_clock> time_point;
static constexpr bool is_steady = false;
對於system_clock,其起點是epoch,即1970-01-01 00:00:00 UTC,其刻度是1個tick,也就是_XTIME_NSECS_PER_TICK納秒。
- high_resolution_clock
typedef steady_clock high_resolution_clock;
high_resolution_clock實際上和steady_clock一樣。
- steady_clock
struct steady_clock
{ // wraps QueryPerformanceCounter
typedef long long rep;
typedef nano period;
typedef nanoseconds duration;
typedef chrono::time_point<steady_clock> time_point;
static constexpr bool is_steady = true;
steady_clock的刻度是1納秒,起點並非1970-01-01 00:00:00 UTC,一般是系統啟動時間,這就是問題的關鍵。steady_clock的作用是為了得到不隨系統時間修改而變化的時間間隔,所以凡是想得到絕對時點的用法都是錯誤的。steady_clock是沒有to_time_t()的實現的,而system_clock是有的。
三種時鍾用在什么時候
- system_clock:用在需要得到絕對時點的場景
auto tp = std::chrono::system_clock::now();
std::time_t tt = std::chrono::system_clock::to_time_t(tp);
std::cout << tt << "seconds from 1970-01-01 00:00:00 UTC" << std::endl;
- steady_clock:用在需要得到時間間隔,並且這個時間間隔不會因為修改系統時間而受影響的場景
auto tp1 = std::chrono::steady_clock::now();
//do something
auto tp2 = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(tp2 - tp1).count() << "microseconds" << std::endl;
- high_resolution_clock:high_resolution_clock是system_clock或steady_clock之一,根據情況使用
常見的錯誤用法
- stdthis_threadsleep_until傳入的是steady_clock::time_point
- 根據steady_clock::time_point得到time_t