[C++11 併發程式設計] 17 超時等待
阿新 • • 發佈:2019-02-01
之前我們看到的所有等待機制都是不會超時的,也就是說,等待某個同步事件的執行緒會一直掛起。有些情況下,我們希望設定一個最長等待時間,使得程式可以繼續與使用者進行互動,使得使用者可以取消這個操作。我們先來看看C++11提供的時鐘類clock:
clock
clock提供瞭如下四種資訊:
- 當前時間
- 存放從clock獲取到的時間的型別
- 時鐘每個tick的週期
- 每個tick的週期是否固定,固定則為“steady”時鐘
Member functions
now [static] |
returns a representing
the current point in time (public static member function) |
converts a system clock time point to (public static member function) |
|
converts to
a system clock time point (public static member function) |
下面是一個簡單的例項,計算不同長度向量中元素的和並列印程式執行的時間:
程式執行結果如下:#include <iostream> #include <vector> #include <numeric> #include <chrono> volatile int sink; int main() { for (auto size = 1ull; size < 1000000000ull; size *= 100) { // record start time auto start = std::chrono::system_clock::now(); // do some work std::vector<int> v(size, 42); sink = std::accumulate(v.begin(), v.end(), 0u); // make sure it's a side effect // record end time auto end = std::chrono::system_clock::now(); std::chrono::duration<double> diff = end-start; std::cout << "Time to fill and iterate a vector of " << size << " ints : " << diff.count() << " s\n"; } }
Time to fill and iterate a vector of 1 ints : 2.93e-06 s
Time to fill and iterate a vector of 100 ints : 2.94e-06 s
Time to fill and iterate a vector of 10000 ints : 8.9962e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00859845 s
Time to fill and iterate a vector of 100000000 ints : 0.948915 s
時鐘的tick週期可以通過std::ratio<x,y>來指定,一秒tick25下的時鐘週期為std::ratio<1,25>,每2.5秒tick一下的時鐘週期為std::ratio<5,2>。
tick週期穩定的時鐘被稱為穩定時鐘,它的is_steady靜態成員變數為true。對於非穩定時鐘,在本地時鐘發生漂移時,會自動進行調整,這就可能導致後執行的now()操作可能比先執行的now()操作得到的時間更小。在多執行緒環境下,超時操作需要使用穩定的時鐘。可以使用std::chrono::steady_clock來獲得穩定的時鐘。std::chrono::system_clock則被稱為實時時鐘,可以被轉換為time_t值,也可以通過time_t轉換為system_clock型別。而std::chrono::high_resolution_clock則提供了系統能支援的最高精度的時鐘。
duration
duration用於指定一個時間段,std::chrono::duration<>類模版的第一個引數指定週期的標示型別(比如int, long或者double),第二個引數指定週期的單位(一個單位代表多少秒)。
例如,以分鐘為單位的週期定義如下,一分鐘為60秒:
std::chrono::duration<short, std::ratio<60, 1>>
以毫秒為單位的週期定義如下,一秒鐘為1000毫秒:
std::chrono::duration<double, std::ratio<1, 1000>>
此外,標準庫在std::chrono名字空間還提供了一系列預定義的週期精度,例如:nanoseconds,microseconds,milliseconds,seconds,minutes和hours。這樣如果要用精度為分秒的週期,可以使用如下程式碼:
std::duration<double, std::centi>;
下面一個例子中,定義了多種型別的duration,並在它們之間進行轉換:
#include <iostream>
#include <chrono>
int main()
{
using shakes = std::chrono::duration<int, std::ratio<1, 100000000>>;
using jiffies = std::chrono::duration<int, std::centi>;
using microfortnights = std::chrono::duration<float, std::ratio<12096,10000>>;
using nanocenturies = std::chrono::duration<float, std::ratio<3155,1000>>;
std::chrono::seconds sec(1);
std::cout << "1 second is:\n";
std::cout << std::chrono::duration_cast<shakes>(sec).count()
<< " shakes\n";
std::cout << std::chrono::duration_cast<jiffies>(sec).count()
<< " jiffies\n";
std::cout << microfortnights(sec).count() << " microfortnights\n";
std::cout << nanocenturies(sec).count() << " nanocenturies\n";
}
程式執行效果如下:
1 second is:
100000000 shakes
100 jiffies
0.82672 microfortnights
0.316957 nanocenturies
基於duration,等待一個期望35毫秒的實現如下:std::future<int> f=std::async(some_task);
if(f.wait_for(std::chrono::milliseconds(35))==std::future_status::ready)
do_something_with(f.get());
等待函式會返回一個狀態來標示是超時了還是等待的時間發生了。如例子所示,等待的是一個期望,如果超時了,返回值為std::future_status::timeout,如果時間發生了,返回值為std::future_status::ready。
基於duration的等待機制使用的是穩定時鐘。