我不能直接添加到David,templatetypedef等給出的優秀答案 - 如果您想避免線程間通信延遲和資源浪費,請不要使用sleep()循環執行線程間通信。
搶佔式調度/調度:
在CPU級,中斷是關鍵。在發生導致其代碼輸入的中斷之前,操作系統什麼也不做。需要注意的是,在操作系統方面,中斷有兩種形式 - 「真正的」硬件中斷,導致要運行的驅動程序和「軟件中斷」 - 這是OS系統從已經運行的線程調用可能會導致該組運行的線程改變。按鍵,鼠標移動,網卡,磁盤,頁面錯誤都會產生硬件中斷。 wait和signal函數和sleep()屬於第二類。當硬件中斷導致驅動程序運行時,驅動程序會執行設計要執行的任何硬件管理。如果驅動程序需要向操作系統發出某個線程需要運行的信號(可能磁盤緩衝區已滿且需要處理),則操作系統會提供一個驅動程序可以調用的入口機制,而不是直接執行中斷 - 返回自己,(重要的!)。
中斷像上面的例子可以使正在等待就緒線程運行和/或可以使運行進入一個等待狀態的線程。在處理完中斷代碼後,操作系統應用其調度算法/ s來確定在中斷之前運行的線程集是否與現在應該運行的集相同。如果是,操作系統只是中斷返回,如果沒有,操作系統必須搶佔一個或多個正在運行的線程。如果操作系統需要搶佔正在處理中斷的CPU內核上運行的線程,則它必須獲得對該內核的控制權。它通過「真正的」硬件中斷來實現這一點 - 操作系統內部處理器驅動程序設置了一個硬件信號,用於硬件中斷運行要被搶佔的線程的內核。
當一個線程是被搶佔進入OS代碼,操作系統可以保存線程的完整上下文。有些寄存器已經通過中斷入口保存到線程堆棧中,因此保存線程的堆棧指針將有效地「保存」所有這些寄存器,但操作系統通常需要做更多工作,例如。可能需要刷新高速緩存,可能需要保存FPU狀態,並且在要運行的新線程屬於與要被搶先的線程不同的進程的情況下,需要將內存管理保護寄存器換出。通常,操作系統儘快從中斷線程堆棧切換到專用操作系統堆棧,以避免在每個線程堆棧上造成操作系統堆棧要求。
一旦保存了上下文,操作系統就可以爲要運行的新線程「交換」擴展上下文。現在,操作系統可以最終加載新線程的堆棧指針,並執行中斷返回以使其新的就緒線程運行。
然後OS不做任何事情。正在運行的線程一直運行,直到出現另一箇中斷(硬或軟)。
要點:
1)OS內核應該被看作是一個大的中斷處理程序,它可以決定中斷返回一組不同的線程數少於中斷的那些的。
2)操作系統可以控制任何進程中的任何線程,並在必要時停止任何線程,而不管它處於什麼狀態或可能運行什麼內核。
3)搶先調度和分派確實會產生在這些論壇上發佈的所有同步等問題。最大的好處是在線程級別對硬中斷的快速響應。如果沒有這些,那麼在PC上運行的所有這些高性能應用程序 - 視頻流,快速網絡等幾乎是不可能的。
4)OS定時器只是一組可以改變運行線程集的中斷之一。 '時間切片'(呃 - 我討厭這個詞),就緒線程之間只有當計算機超載時纔會發生,即。就緒線程集大於可用於運行它們的CPU內核數。如果任何旨在解釋操作系統調度的文本在「中斷」之前提到「時間片」,它可能會導致比解釋更多的混淆。定時器中斷只是「特殊的」,因爲很多系統調用都有超時時間來備份它們的主要功能(OK,sleep(),超時是主要功能:)。
只是想知道,不是這個等待函數如何在內部工作嗎? (顯然不包括例外情況。) – Mehrdad 2012-01-12 07:14:52
@ Mehrdad-通常沒有。通常這些線程被放置在一個「等待隊列」中,而沒有給出任何處理器時間。當某些事件發生時會喚醒它們,它們被放回到運行隊列中,以便它們被安排。這意味着,如果在任何時候只有兩個或三個線程處於活動狀態,則可以擁有一百萬個睡眠線程,而不會有任何性能損失。 – templatetypedef 2012-01-12 07:16:05
@templatetypedef:那麼OS究竟該如何確定線程是否應該在特定的時間片喚醒?它不應該在每個時間片檢查循環中線程的狀態嗎? – Mehrdad 2012-01-12 07:20:52