HOWTO · C++
在 C++ 中新增定時延遲
本教程將為你提供有關在 C++ 程式中新增定時延遲的簡要指南。
本頁內容
C++ 程式可以透過平台 API,或標準函式庫的執行緒等待功能,暫停目前的執行緒。選擇時可考量可攜性,以及等待目標是時間長度還是時鐘上的時間點:POSIX 系統的 sleep() 以整秒為單位,usleep() 以微秒為單位;C++11 的 sleep_for() 和 sleep_until() 則分別接受時間長度與時間點。這些呼叫都會暫停呼叫它的執行緒,但不保證執行緒會在某個精確時刻恢復執行。
選擇適合的 C++ 延遲 API
一般應用程式若需要可攜的 C++11 相對等待,請使用 sleep_for()。若工作需要等到時鐘上的某個期限,請使用 sleep_until()。POSIX 函式 sleep() 和 usleep() 適合已綁定 POSIX 的程式,但不是可攜的 C++ 功能。Windows 則提供自己的 Sleep() API,參數單位是毫秒。
延遲會阻塞呼叫它的執行緒。如果使用者介面、伺服器或工作執行緒集區需要保持回應,請暫停專用執行緒,或使用框架提供的非同步計時器;不要阻塞主執行緒或事件迴圈執行緒。
使用 sleep() 執行以整秒計算的平台專屬延遲
C++ 沒有定義可攜的 sleep() 函式。在 POSIX 系統上,請透過 <unistd.h> 宣告它,並呼叫 sleep(seconds)。若訊號中斷等待,它會傳回尚未等待的整秒數;若指定的時間已經過去,則傳回零。在 Windows 上,請引入 <Windows.h> 並呼叫 Sleep(milliseconds);其單位是毫秒,因此延遲一秒可呼叫 Sleep(1000)。POSIX 與 Windows 的呼叫在名稱、標頭檔和單位上都不同。<Windows.h> 的用法也可參考Windows.h 指南;該指南目前只有英文版,沒有繁體中文版本。
例如,引入 <unistd.h> 後,可在 POSIX 系統上呼叫 sleep(2);。在 Windows 上,則是在引入 <Windows.h> 後使用 Sleep(2000);。請依目標平台選擇對應的分支;只有 POSIX 的宣告,並不會讓 Windows 上也能使用 sleep()。
使用 usleep() 執行 POSIX 微秒延遲
在 POSIX 系統上,usleep() 宣告於 <unistd.h>,接受以微秒為單位的時間長度。例如,usleep(250000); 會要求暫停四分之一秒。它是 POSIX 介面,不是可攜的 C++ 功能;部分平台或功能設定可能不提供它,因此跨平台的 C++ 程式請使用 sleep_for()。等待完成時,此函式傳回 0;若等待遭到中斷或因其他原因失敗,則傳回 -1。若呼叫端需要處理中斷情況,請檢查傳回值。由於作業系統會自行排程執行緒,實際經過的時間可能長於指定的間隔。
使用 sleep_for() 執行相對延遲
引入 <thread> 和 <chrono>,即可等待一段相對時間。sleep_for() 至少會暫停目前的執行緒達到指定時間,實際情況仍受排程與資源競爭影響。以下完整的 C++11 程式會暫停 200 毫秒,接著輸出確認訊息。請執行此範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
#include <chrono>
#include <iostream>
#include <thread>
int main() {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Wait complete\n";
}
Wait complete
請使用能清楚表達預期單位的時間長度型別,例如 std::chrono::seconds(2) 或 std::chrono::milliseconds(250)。等待只會影響呼叫它的執行緒;排程延遲可能使實際經過的時間長於傳入函式的時間長度。
使用 sleep_until() 等待時間點
sleep_until() 同樣來自 <thread>,但它接受的是時鐘上的時間點,而非時間長度。將一段時間加到時鐘的 now() 值上,即可建立未來的期限;例如 std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::seconds(3));。這會等待至 steady_clock 上的該時間點;此時鐘適合用來測量時間間隔,不會像掛鐘時間那樣被調整。若期限已經過去,呼叫便不會再增加等待時間。此函式不會傳回值,而排程可能使執行緒直到期限之後才恢復執行。
若期限是以經過時間計算,請優先使用 steady_clock,避免系統時鐘校正改變目標時間。只有在目標是掛鐘時間時才使用 system_clock,並將等待期間時鐘可能變動的情況納入考量。和 sleep_for() 一樣,此呼叫會阻塞目前的執行緒。
選擇合適的延遲方式並考量排程
對可攜的 C++11 程式而言,需求若是「等待這段時間」,請使用 sleep_for();若是「等到這個期限」,則使用 sleep_until()。只有在適合採用 POSIX 專屬行為時才使用 sleep() 或 usleep();Windows 專屬程式則使用 Windows 的 Sleep()。請留意各 API 的單位:sleep() 接受秒,usleep() 接受微秒,Windows 的 Sleep() 接受毫秒,而 <chrono> 以具名型別表示時間長度。
這些 API 都不是精確計時器。指定的時間是最短等待目標,並不保證執行緒會在該時刻恢復;排程、資源競爭和中斷行為都會影響程式何時繼續執行。若短暫等待不應阻塞執行緒,請使用平台或框架提供的非同步計時器。了解這些差異後,就能依照程式的可攜需求與計時方式,選擇合適的延遲功能。