睡眠 (系統呼叫)

電腦程式(或處理程序、任務或執行緒等)進入不活躍狀態並持續一段時間,稱為「睡眠」。當引發程式睡眠的程式碼所設定的內部計時器歸零,或是此程式收到喚醒訊號或中斷時,程式將恢復執行。

睡眠中的程式也有可能不經喚醒而直接被終止。

用法

睡眠指令通常需要輸入一個參數,以說明程式睡眠至少多長時間後才恢復執行。這一時間參數的單位通常是秒[來源請求],有些作業系統可以提供更高精度,例如以毫秒或微秒作為單位。

Windows

Windows 作業系統中,Sleep()函式僅有一個參數,即以毫秒計的睡眠時間。[1]Sleep()函式包含於 kernel32.dll 中,但是原生作業系統的批次檔卻並不支援這一指令。安裝諸如Windows 2003 Resource Kit等執行環境後,使用者便可使用這一指令。[2]

Unix

類Unix作業系統中,sleep()函式使用以秒做單位的無符號整數作為輸入參數。[3]如果需要更精確的控制睡眠時間,可以使用 nanosleep()函式。[4]

C語言樣例

Windows 作業系統中:

Sleep(2*1000);  // 睡眠2秒

類Unix作業系統中:

sleep(2);       // 睡眠2秒

底層功能

 
當使用 ps -aux 指令列出當前主記憶體中的所有處理程序時,列標題為 STAT 的列內容就是處理程序當前的狀態。其中含有標識 S 的處理程序就在睡眠狀態(R為執行狀態)
圖中沒有處理程序處於不可中斷睡眠。

睡眠使得執行緒或處理程序讓出他們占用的剩餘時間片,並在 「不在執行」狀態等待一段時間。雖然這段程式在睡眠前被設定了最短睡眠時長,可這並不意味著這段時間結束後此程式能夠立即恢復運作——這取決於 排程程式 的分配、等待喚醒的程式的優先級和其他一些因素。在 POSIX 系統中, nanosleep 及其他類似的系統指令會被中斷訊號中斷,相應程式也會停止睡眠。而 sleep 媒體櫃函式卻不盡相同,在一些老一點的作業系統中,它是通過呼叫 alarm 系統指令實現的,因而必須通過送訊號的方式才能運作。

在Windows中,由於除了終止執行訊號外沒有專門的訊號可以用於打斷,睡眠函式是不可中斷的。不過,Windows提供了 SleepEX 函式來實現通過 APC 呼叫控制睡眠處理程序的喚醒。

嚴格說來,一個執行緒也可以由於其他執行緒終止執行或丟擲異常被喚醒。

使用場景

一些系統程式在事件輪詢過程中從不被終止,只是在每個周期開始前進入睡眠狀態,等待著某些事件的發生喚醒它們。當收到事件之後,它們就被喚醒去處理這些事件,然後進入下一個周期的等待。

還有一些程式周期性的從睡眠中恢復執行並收集事件。當執行恢復,程式拉取事件列表和狀態變更情況,然後針對睡眠時發生的事件做相應處理,完成後再次進入睡眠,等待下一個時隙。這類事件被稱作心跳事件,或「持久連接[5]」訊號,可由上述類型的周期性程式傳送。

sleep()函式還在程式執行節奏需要放緩的時候被呼叫。例如長時間高負荷執行程式時應有包含睡眠函式的程式碼來減輕硬體過熱帶來的麻煩[6],或是解決遺留程式碼中不為人知的奇妙程式錯誤。相比於使用仿真器實現的周期平衡的程式,睡眠-執行周期發生的程式的缺點在於如果切換速度不夠快,互動式程式就會有明顯的延遲,如果太快,喚醒時間就太短以至於無法完成全部工作。[7]

不可中斷睡眠

不可中斷睡眠指的是在此狀態的程式無法對外界訊號做出任何立即的回應,只有在為它提供足夠的正在等待的資源或是睡眠時間結束它才會開始執行。這類睡眠常見於硬體驅動程式等待磁碟或網路輸入輸出結束。當處理程序處於不可中斷睡眠狀態,睡眠期間的訊號會不斷堆積到佇列裡面去。

在類Unix作業系統中,使用指令ps -l可以列出當前終端的全部處理程序,其中標識處理程序狀態的列使用程式碼 D 表示不可中斷睡眠[8]。這類處理程序連SIGKILL這樣的無條件終止都沒辦法結束處理程序,結束他們最簡單的方法就是重新啟動系統。[9][10]但Linux作業系統在2.6.25版本[11]以後引入了一種新的睡眠狀態TASK_KILLABLE,處於這種狀態的處理程序在ps命令中同樣以程式碼D顯示,這樣的處理程序只可以被SIGKILL訊號終止,用於在某些場景下替代原來的不可中斷睡眠,比如當處理程序呼叫NFS介面得不到應答,這時可以通過kill -9命令來終止處理程序。

另見

參考文獻

  1. ^ MSDN Library Reference - Sleep(). [2019-06-25]. (原始內容存檔於2018-01-22). 
  2. ^ batch file sleep command. [2019-06-25]. (原始內容存檔於2016-03-03). 
  3. ^ UNIX Man Page - SLEEP(3) 網際網路檔案館存檔,存檔日期2011-07-20.
  4. ^ nanosleep.3p - Linux manual page. [2019-06-25]. (原始內容存檔於2020-10-20). 
  5. ^ 关于 HTTP 协议中的 keep-alive | Laravel China 社区. learnku.com. [2019-06-25]. 
  6. ^ mion. BES – Battle Encoder Shirase 1.6.3 (stable) & 1.7.4 for Windows 7/XP/2000. mion.faireal.net. 2016-12-06 [2017-02-09]. (原始內容存檔於2021-04-15). 
  7. ^ Marletta, Angelo. CPULIMIT. GitHub. 2015-03-12 [2017-02-09]. 
  8. ^ top(1) - Linux manual page. man7.org. 2016-12-12 [2017-02-09]. (原始內容存檔於2021-02-18). 
  9. ^ Processes in an Uninterruptible Sleep (D) State. Novell. 2009-02-21 [2017-02-09]. (原始內容存檔於2018-02-01). 
  10. ^ Fusco, John. The Linux Programmer's Toolbox. Pearson Education. 2007-03-06. ISBN 9780132703048. 
  11. ^ Change log of linux 2.6.25.. [2024-04-12]. (原始內容存檔於2024-05-02).