睡眠 (系統調用)

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

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

用法 編輯

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

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].