2013-02-09 147 views
22

所以這裏有兩個問題。首先,(是的,我已經搜索過,但想澄清),用戶線程和內核線程之間有什麼區別?簡單地說,一個是由用戶程序生成的,另一個是由操作系統生成的,後者可以訪問特權指令?它們在概念上是相同還是在線程本身存在實際差異?線程:爲什麼所有用戶線程都必須映射到內核線程?

其次,我的問題的真正問題是:我正在使用的這本書說「用戶線程和內核線程之間必須存在關係」,並列出這種關係的不同模型。但該書未能清楚解釋爲什麼的用戶線程必須總是將映射到特定的內核線程。爲什麼是這樣?

回答

22

A 內核線程是由操作系統維護的線程對象。它是一個能夠被處理器調度和執行的實際線程。通常,系統線程是具有權限設置,優先級等的重量級對象。內核線程調度程序負責調度內核線程。

用戶程序也可以創建自己的線程調度程序。他們可以創建自己的「線程」並模擬上下文切換以在它們之間切換。但是,這些線程不是內核線程。每個用戶線程都不能真正自己運行,而用戶線程運行的唯一方式是如果內核線程實際被告知執行包含在用戶線程中的代碼。也就是說,與內核線程相比,用戶線程具有重大優勢。它們可以更加輕量級,因爲它們不一定需要擁有自己的優先級,可以由單個進程管理(可能有關於需要運行什麼線程的更好信息),並且不會創建大量的內核對象用於安全和鎖定的目的。

用戶線程必須與內核線程關聯的原因在於,用戶線程本身就是用戶程序中的一堆數據。內核線程是系統中真正的線程,因此爲了讓用戶線程取得進展,用戶程序必須讓其調度程序獲取用戶線程,然後在內核線程上運行它。用戶線程和內核線程之間的映射不一定是一對一(1:1);您可以讓多個用戶線程共享相同的內核線程(一次只能運行其中一個用戶線程),並且您可以擁有一個用戶線程,該用戶線程在1:n映射中跨不同的內核線程進行輪換。

1

我認爲一個真實世界的例子將清除混淆,所以讓我們看看Linux中的事情是如何完成的。

首先Linux不區分進程和線程,可以調度的實體在Linux中稱爲task,由task_struct表示。因此,無論何時執行fork()系統調用,都會創建一個新的task_struct,它保存與新任務關聯的數據(或指針)。

所以在Linux世界裏,一個內核線程意味着一個task_struct對象(結構)。因爲調度程序只知道可以分配給不同CPU(邏輯或物理)的這些實體。換句話說,如果您希望Linux調度程序調度您的過程,則必須創建一個task_struct。

用戶線程是由某些執行環境(從現在開始的EE)(如JVM)在內核之外支持和管理的內容。這些EE將爲您提供一些功能來創建新線程。

現在讓我們來回答你的問題

why a user thread must always be mapped to a specific kernel thread. 

比方說,你用你EE創造了一些線程。最終它們必須由CPU執行,從上面的解釋中我們知道你(線程)必須有一個task_struct才能分配給某個CPU。這就是映射必須存在的原因。您的EE有責任創建task_structs。

如果您的EE使用多對一模型,那麼它將只爲所有線程創建一個task_struct,並且它會將所有這些線程調度到該task_struct。考慮到有一個CPU(task_struct)和許多進程(EE中創建的線程),您的操作系統(EE)會將這些進程複用到單個CPU上。

如果它使用一對一模型,那麼EE中創建的每個線程都會有一個task_struct。所以當你在EE中創建一個新線程時,相應的task_struct會在內核中創建。 (如果你希望CPU可以被映射到相應的內核線程上,那麼CPU就會被映射到相應的內核線程上)執行它們)。