概要
多線程是一種將一個應用程序切分成“線程”並按步驟運行程序的其他部分的平台開發能力。在大多數編程語言中,你會有一個Main()方法,每行代碼都會順序執行,只有當前面的一行代碼執行完,后面的代碼才會執行。線程是操作系統常規多任務能力的一個組成部分並允許應用程序的一部分與其他對象的分別執行的一個特定對象,所以不在應用程序通用執行順序范疇內。在這一章,我們將討論多任務的不同類型。
另外一個概念是自由線程, 它對於大多數C++或者Java程序員來說已經很熟悉了;我們將定義這個概念並進一步討論在C#中是如何實現的並將簡要比較自由線程模型和其他模型,比如Visual Basic 6.0 的apartment-threading 模型。我們不打算在這上面浪費太多筆墨,因為這不是一本歷史書同時這本書也不是關於Visual Studio 6.0的。然而理解是什么將這些模型分開將會幫助你理解自由線程技術的曼妙。這一章的內容是幫助你理解本書余下部分的基礎,從本章你將學到(不保證學會):
1. 從概念上講,什么是線程?
2. 多種多任務和線程模型的比較。
3. 線程在哪?它們是如何分配處理器時間的?
4. 如何使用中斷和優先級控制並管理線程?
5. 應用程序域的概念,以及它們如何比一個簡單的處理環境能向你的應用程序提供更好的安全性控制。
線程定義
在這一章的結尾,你將理解以下內容:
1. 什么是多任務?不同類型的多任務是什么樣子的?
2. 什么是進程?
3. 什么是線程?
4. 什么是主線程?
5. 什么是子線程?
多任務
你可能知道,多任務的概念是指一個操作系統在同一段時間內運行多個應用程序的能力。例如,當你在讀這篇文章時,微軟Outlook 也在運行同時你還打開了兩個word 文檔,通過系統跟蹤工具可以知道后台有更多程序在運行。當來回切換程序時,看起來它們好像同時運行,當然這里說的”程序“的概念有點模糊,事實上我們指的是進程。在下一章我們將會對”進程“做進一步介紹。
經典說法是多任務實際上有兩種不同的類型。Windows 目前在線程中僅使用了其中的一種,我們將在本書中廣泛探討這種模式。然而,我們也要看看之前的多任務類型以便於我們可以理解這兩種類型的不同以及采用當前方法的優勢。
在Windows 的早期版本-比如Windows 3.x-以及其他操作系統中,只有當一個線程通過釋放自己占用的處理器給其他正在運行的程序時,一個程序才被允許執行。因為它取決於應用程序與其他正在運行程序的合作,這種類型的多任務稱作協作式多任務。這種類型的多任務的劣勢是一旦一個程序沒有釋放處理器,那么其他應用程序將會被掛起。實際情況是正在運行的應用程序卡住了,其他應用程序排隊等候。這跟在銀行排隊辦業務很相似。每個櫃台在同一時間只能服務一個客戶。客戶在他們的事務完成之前不可能從櫃台窗口前離開。一旦完成了,櫃台可以按順序服務下一個人。它不在乎一個客戶將要在窗口花費多長時間。即便一個人只想存一張支票,他也必須等待前面那個人的5個事務全部完成。
幸運的是,我們將不會在Windows 2000 和XP 以及它們之后的版本中碰到這個問題,因為與Windows之前版本使用的多任務方法完全不同了。操作系統在中斷一個應用程序並允許其他應用程序執行之前會允許被中斷程序執行一小段時間。這種多任務的中斷類型成為”搶斷式多任務“。“搶斷式”簡單的定義就是中斷一個程序來允許另外一個程序執行。重點需要注意的是一個應用程序可能還沒有完成它的任務,但是操作系統將要允許另外一個程序使用它的處理器時間。銀行櫃台的例子在這里就不適用了。在現實世界中,這就好比銀行櫃台中斷了一個客戶正在執行的業務然后允許其他客戶開始他們的事務。這也不意味着下一個客戶可以完成他們的事務。櫃台可能會一個接一個用戶的中斷-最終服務到第一個客戶。這很像人類大腦在處理社交和其他任務時候的表現。雖然搶斷式多任務解決了處理器被鎖住的問題,但它也有自己的問題,正如你所知道的那樣,一些應用程序可能會共享數據庫連接和文件等資源。如果兩個應用程序在同一時間訪問同樣的資源會發生什么?一個程序可能把數據給改了,然后它被中斷,允許另外一個程序來再一次改數據。現在兩個程序修改了同一份數據。但兩個程序都假定自己獨占了數據。讓我們來看圖1中的一個簡單場景。
圖1
在步驟1,程序A從一個數據存儲器獲取一個整型值並把它放到內存中。這個整型變量被設置為10. 應用程序A然后被中斷並強制等待程序B。步驟2開始,應用程序B獲取同樣的整型值10. 在步驟3, 應用程序B將這個值加1. 變量然后在步驟4被存儲到內存中。在步驟5,應用程序A也增加這個值。然而,因為它們都在變量值為10時獲取到對其的引用,所以在程序A設置完這個值以后它仍然為11. 而期待的結果是12. 這兩個程序都不知道還有其他程序訪問這個資源,最終它們同時嘗試增加的值有了一個錯誤的結果。如果這發生在一個引用計數器或者一個負責訂機票的客戶端會怎么樣?
這個問題與多任務搶占有關,而且已經通過同步的方法解決,具體會在第三章介紹。
進程
當一個程序運行了以后,內存以及其他資源都將分配給它。內存和資源的物理隔離稱作一個進程。當然,一個程序可能會有不止一個進程。“程序”和“進程”並不是一個意思。分配給一個進程的內存與其他進程隔離而且只有自身可以訪問。
在Windows操作系統中,你可以打開Windows 任務管理器來查看正在運行的進程。在任務欄的空白處單擊右鍵然后選擇任務管理器,打開的任務管理器包含三個選項卡(在最新的Windows 版本中,已經有不止三個選項卡了):應用程序,進程和性能。進程選項卡顯示進程名,進程ID(PID), CPU使用率,進程到目前為止使用的處理器時間以及它正在使用的內存大小。為了便於理解,程序和進程分別有不同的選項卡。程序可能有多個進程。每個進程有它自己的數據,執行代碼和系統資源。
下一篇我們將會繼續介紹線程…