大家好,最近我在工作當中遇到了一個函數,就是c++中的sleep_for函數,說實話,這還真是我第一次見到這個函數,所以我就花了點時間研究了一下這個函數,現在想總結一下分享給大家。
一、sleep_for函數的簡介
二、sleep_for函數用到的情景
三、sleep_for函數,sleep函數以及yield函數三者的區別
四、關於c++中chrono函數的使用
五、關於c++中時間的獲取方法
一、sleep_for函數的簡介
先簡單說一下sleep_for這個函數的情況。
1、這個函數是一個線程函數,換句話說他的作用域只作用於當前線程,因此,包含它的庫也就是thread庫。
2、這個函數的原型為
sleep_for(const chrono::duration<_Rep, _Period>& __rtime)(關於chrono的部分我們待會再說,我們只要知道這是個時間間隔)
3、這個函數要實現的目的就是線程阻塞,換句話說就是要讓當前的線程休眠一段時間(具體時間就是我們傳進去的參數),而其他進程不休息。
最后舉一個使用例子:std::this_thread::sleep_for(std::chrono::miliseconds(50)) //表示讓該線程休眠50ms
二、sleep_for用到的場景
這里說一下我們為什么要用sleep_for,是這樣的,我們這個代碼中要發給底層硬件發送一條指令,我們知道硬件的處理速度是有一定時間的,所以為了不影響后續的代碼的運行,所以需要
做一個線程阻塞,保證其在這段時間內硬件處理完畢。
三、關於sleep_for,sleep以及yield函數三者的區別
關於sleep_for,它還有一個類似的函數,叫yield,他的作用域,參數和sleep_for是一樣的,它的函數原型是這樣的:
std::this_thread::yield: 當前線程放棄執行,操作系統調度另一線程繼續執行。即當前線程將未使用完的“CPU時間片”讓給其他線程使用,等其他線程使用完后再與其他線程一起競爭"CPU"。
另外我們在系統中還有一個阻塞函數sleep函數,所以我們說一說三者的區別。
我們先來說sleep函數,我們有兩點要說明:
1、sleep函數是系統函數,換句話說它不需要c++11支持,只要有編譯器就能找到這個函數。
2、sleep函數是進程阻塞函數,換句話說一旦調用這個函數,當前進程當中所有的線程全部阻塞。
接着我們說其他兩個函數:我們來看一下代碼:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
int n=0;
std::thread t1(function1, std::ref(n));
std::thread t2(function2, n);
t1.join();
t2.join();
w.show();
return a.exec();
}
void function1(int &n)
{
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
n++;
if (n==10) {
mux.lock();
g_flag = true;
mux.unlock();
} else if(n == 15) {
mux.lock();
// std::this_thread::sleep_for(std::chrono::seconds(5));
mux.unlock();
}
else if (n == 20) {
mux.lock();
g_flag = false;
mux.unlock();
} else if (n == 30) {
mux.lock();
g_flag = true;
mux.unlock();
}
else {
std::cout<<"F1 is:"<<n<<std::endl;
}
}
}
void function2(int n)
{
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
// std::this_thread::yield();
n++;
std::cout<<"F2 n: "<<n<<std::endl;
mux.lock();
bool flag = g_flag;
mux.unlock();
if (flag) {
} else {
}
}
}
這里有兩個線程,依次打印n的值,我們首先是不加yield語句打出來的結果
看到了嗎?兩個函數的執行過程是隨機的,這是因為CPU時間片調度算法本身就是隨機的。
接下來我們看一下加上yield的效果。
這個效果是是什么呢?F1永遠在F2前面,另外,F2中的n也在不斷增長
好了,到這里我們可以總結一下yield函數了,這個函數要注意兩點:
1、std::this_thread::yield(); 是將當前線程所搶到的CPU”時間片A”讓渡給其他線程(其他線程會爭搶”時間片A”,
等到其他線程使用完”時間片A”后, 再由操作系統調度, 當前線程再和其他線程一起開始搶CPU時間片.
就是說第一,遇到這個函數會優先讓其他線程執行,第二,其他線程執行完我還是會執行的。
四、關於c++中chrono函數的使用
這個庫是c++11定義出來的關於處理時間的庫,有了它處理時間問題就會非常方便了。我們在這里簡單介紹一下這個庫的一些常用方法。
1、duration_cast(這個主要實現的功能就是可以將單位進行轉換,比如說我們獲取到的系統時間可能是毫秒,但是我們要把他換算成秒怎么辦,就用這個)。
2、system_clock::now(這個函數的主要目的就是獲取到當前系統時間,注意這個時間是當前時間與1970年1月1之間的差值,單位是time_point)
3、time_since_porch (這個函數也是當前時間與1970年1月1日之間的差值,單位是duration)
4、localtime(間隔)(這個函數可以將當前時間與1970年的差值,轉換成包含今天年月日的結構體,不過注意,傳進去的一定是秒)
5、strftime函數(這個函數可以將結構體指針轉換成包含時間格式的字符串數組)
6、to_time_t(將timepoint時間轉換成time_t)
五、時間函數
首先我們說一下,時間到底有啥用,其實我想了想,其用途無非就是兩點,第一獲取到當前的年月日時分秒,第二就是計算兩段代碼相隔的時間。所以我就着重說這兩部分。
1、獲取到當前時間的年月日
無論是什么函數,他的流程一定是這樣的。獲取到time_point值,然后獲取到tm的值,最后獲取到年月日時分秒。
1、先說第一種方法
auto now = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count(); //獲取到time_point的值並將其轉換成秒
ts = localtime(&now) //獲取到當前的tm值
int year = ts.tm_year + 1900;
int month = ts.tm_mon + 1;
int day = ts.tm_mday;
int hour = ts.tm_hour;
int minute = ts.tm_min;
int second = ts.tm_sec;
獲取到當前年月日時分秒的值
2、再說第二種方法
auto tn = std::chrono::system_clock::now(); // 獲取到time_point
time_t now1 = std::chrono::system_clock::to_time_t(tn); // 獲取time_t的值
ts = localtime(&now); // 獲取tm的值
const char *fmt = "%Y-%m-%d %H:%M:%S";
strftime(buf, sizeof(buf), fmt, ts); // 將其轉換成字符串的形式
2、獲取到當前程序運行的時間
auto t0 = std::chrono::system_clock::now();
j++;
auto time2 = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>
(std::chrono::system_clock::now() - t0).count()<<std::endl;
通過得到時間戳相減得到最終的值,另外我測的話一行代碼時間58ns,所以只好設置na秒級別了。
這就是通過sleep_for函數引發的思考。