都說操做系統是用戶體驗驅動其發展的,在好久好久的Micrisoft的16位Windows操做系統中,那是單線程並且是不能搶佔的CPU的操做系統,這樣致使了當某個線程發生死鎖或者不能正確的運行的時候,整個操做系統都不能運行,處於一種凍結的狀態。用戶只能無奈的按下Reset按鈕來進行重啓。這樣會致使以前運行的全部的數據都會丟失。所以,新的內核就被設計出來了。--我只是知識的搬運工算法
在新的OS內核中,進程實際是應用程序的實例要使用的資源的集合。每一個進行都被賦予了一個虛擬地址空間,確保在一個進程中使用的代碼和數據不會被另一個進行所訪問。而線程的職責是對CPU進行邏輯的虛擬化。編程
線程的開銷 安全
在建立,銷燬一個線程的過程當中,存在着一些巨大的開銷。這些開銷有時間上,也有空間上面的。數據結構
線程內核對象(Thread-kernel object)多線程
這種數據結構包含着一組對線程進行描述的屬性,這些屬性通常是用於CPU的調度,例如線程的優先級,等待的時間等等。同時還包括了線程的上下文(Thread Contexgt),這是CPU寄存器集合的內存塊所存放的信息的副本。函數
線程環境塊(thread environment block)spa
TEB是在用戶模式中分配的初始化的內存塊。TEB耗用一個內存頁(4KB)。TEB包含着異常處理鏈首。線程進入的每一個try塊都在鏈首插入一個節點;線程推出try塊是,從鏈表中刪除該節點。TEB還包含着線程的「線程本地存儲」數據,以及由GDI和OpenGL圖形使用的一些數據結構。操作系統
用戶模式棧(User-model stack)線程
這就是常說的用戶棧,用於存放傳給方法的形參和方法中自定義的實參,已經當前方法返回的時候,線程應該從那個地方開始執行。Windows的默認用戶模式棧的大小爲1M。設計
內核模式棧
當應用程序代碼想操做系統中的內核模式函數傳遞實參時,還會使用內核模式棧。出於對安全的考慮,全部由應用程序向內核函數傳遞的參數,都會先複製到內核模式棧中。因爲程序不能訪問內核模式棧,因此參數一經複製過去內核模式棧中,程序便不能修改其值。其實這個內核模式棧在功能上跟用戶模式棧的做用是同樣的,都是用於存儲傳給方法的形參,已經方法中自定義的實參,以及函數的返回地址。特別之處就是,應用程序不能修改裏面的值,只能由內核函數進行修改,從而達到了安全。
DLL線程鏈接和線程分離通知
上面所說的三個開銷都是對於內存的開銷,這個DLL線程鏈接和線程分離通知倒是時間上面的開銷。不過這也是相對的來講的,由於上面的三個開銷,在分配內存,初始化內存過程當中,也必須花費不少的時間。在建立一個新的線程的時候,Windows都會調用進程中加載的全部非託管DLL的DllMain方法,並向這個方法傳遞一個DLL_THREAD_ATTCH標誌。相似的,終止線程的時候,也會調用這個DllMain方法,並傳遞一個DLL_THREAD_DETACH標誌。由於有些DLL須要獲取這些通知,才能爲進程中建立/銷燬的每一個線程執行特殊的初始化或者清理操做。事實上,每一個進程都會加載不少非託管的DLL文件,因此初始化或者銷燬一個線程,便須要調用多個的DllMain方法。
CPU調度時上下文切換的開銷
上下文切換的開銷主要集中在兩個方面:
不使用ThreadPool而本身建立一個線程的原則
通常狀況下,要爲不會阻止其餘線程的相對較短的任務處理多個線程而且不須要對這些任務執行任何特定調度時,使用 ThreadPool 類是一種最簡單的方式。 可是,有多個理由建立您本身的線程:
線程的優先級
在Windows中,線程的優先級是從0(最低)-31(最高)的。通常CPU是根據線程的優先級來調度線程的。若是當前調度的線程的線程的優先級是10,若是忽然線程的就緒隊列中,來了一個優先級爲15的線程,那麼操做系統會強制的進行線程的切換,來立刻調度優先級爲15的線程,這被稱爲搶佔式調度。
在實際編程中,咱們是看不到這0-31的優先級的,這是由於Windows只是公開了這些優先級的一個抽象。特別要說明的的是,線程的優先級由進程的優先級類和線程的相對優先級來決定。
|
進程優先級類 |
|
|
|
|
|
相對線程優先級 |
Idle |
Below Normal |
Normal |
Above Normal |
High |
Realtime |
Time-Cirtical |
15 |
15 |
15 |
15 |
15 |
31 |
Highest |
6 |
8 |
10 |
12 |
15 |
26 |
Above Normal |
5 |
7 |
9 |
11 |
14 |
25 |
Normal |
4 |
6 |
8 |
10 |
13 |
24 |
Below Normal |
3 |
5 |
7 |
9 |
12 |
23 |
Lowest |
2 |
4 |
6 |
8 |
11 |
22 |
Idle |
1 |
1 |
1 |
1 |
1 |
16 |
這裏要特別說明的是,Windows爲本身保留了優先級0和Realtime範圍,同時CLR也爲本身保留了Idle和Time-Cirtical範圍的優先級。程序的線程絕對優先級是由進程優先級類和相對線程優先級所共同決定的,同時咱們不該該去更改進程的優先級。由於在正常狀況下,進程根據其啓動它的進程來分配優先級。大多數進程都是由Windows資源管理器啓動,後者在Normal優先級類中生成他們的全部子進程。因此咱們在Thread.Priority中只有Highest,Above Normal,Noraml,Below Normal,Lowset這幾種,相對應的優先級是6,7,8,9,10。
圖1 Spy++中查看Chrome的某個線程的信息
前臺線程和後臺線程
前臺線程和後臺線程的主要區別是,進程中只要存在沒有完成的前臺線程,進程就不會被銷燬。換句話說就是,若是全部的前臺線程都完成了,進程就會被銷燬,即便是存在未完成任務的後臺線程。咱們能夠經過設置Thread.IsBackground來把線程設置爲前臺線程或者是後臺線程。經過ThreadPool(其中ThreadPool.QueueUserWorkItem,Timer,Task等等都是經過ThreadTool來實現的)來實現的線程都是後臺線程,經過Thread類來實現的線程都是前臺線程。