C# 線程手冊 第四章 線程設計原則 MTA 線程模型


一個STA和一個MTA線程單元最大的不同是再同一個線程單元中可以有多個線程運行並可以使用所有共享數據。如圖2所示。

2012-3-4 21-52-39

圖 2

由於MTA線程模型支持多線程並發執行,所以處理多線程間全局數據的同步問題就變成了調用方的事情了。關於同步問題我們已經在上一章描述過。

確定線程模型

可以使用Thread 類中的ApartmentState 屬性來設置一個線程的線程模型。ApartmentState 枚舉定義了.NET 支持的線程模型類型。

2012-3-4 21-57-49

正如我們之前學到的,你應該僅當你訪問一個STA線程的COM組件時你才應該把線程標記為STA。否則,你的線程模型默認都是MTA。

設計多線程應用程序

一個多線程程序有多於兩個線程,它可以通過並發實現重要性能提升,不管是否並發執行線程。線程並發執行意味着多於兩個線程在同一時間執行。並發是指>=2個線程在>=2個處理器中同步執行。

在這部分,我們將探討設計多線程應用時的考量和問題。在你開發應用程序之前,你應該問問你自己以下問題:

  1. 把程序分成小塊來運行在不同線程上是否可行?

  2. 如果可以將一個線程分成小塊,那么該如何進行拆分呢?有沒有標准呢?

  3. 主線程和工作線程的關系是什么?這定義了應用程序中的任務之間的關系。

你可以通過查看程序來得到第一個問題的答案。例如,你的程序需要頻繁的I/O操作,比如讀取一個XML文件或者查詢一個數據庫,又或者執行很多CPU敏感型處理任務,比如加密和解密數據以及哈希運算等等。如果是這樣,這些操作可能會阻塞你程序的主線程。

如果你已經確定了你程序中的一部分可以成為獨立線程的執行體,那么接下來你應該問問自己以下問題:

  1.  每個確定的任務都要使用單獨的全局資源嗎?

  例如,如果你為程序確定了兩個潛在的線程且它們都要訪問同一個全局資源的話,比如一個全局變量或者一個DataSet對象,然后如果兩個線程都嘗試在同一時間訪問全局資源的話,可能會導致數據不一致或者數據崩潰,正如之前章節描述的那樣。防止這類問題發生的唯一方法就是在全局資源上使用鎖,這樣就可以讓多線程互斥訪問。如果兩個任務都要使用同一個全局資源,那么最好不要把它們拆分成兩個任務。對於一些資源來說,你可以使用Monitor類阻止線程鎖住。這也在第三章介紹過。

  2.  阻塞一個線程需要多長時間?

  使用獨立全局資源創建應用程序並不總是可能的。例如,假設程序中有兩個任務依賴同一個全局DataSet對象。如果第一個任務需要花費很長時間來填充DataSet對象,那么你應該鎖住DataSet對象以防止並發問題。這里是第一個任務的偽代碼表示:

  1) 打開數據庫連接

  2) 鎖住全局DataSet 對象

  3) 執行查詢

  4) 使用從數據庫查詢到的50,000 行數據填充DataSet對象

  5) 解鎖DataSet 對象

  在這種情況下,第二個任務需要在它能訪問DataSet對象之前等待很長時間,僅當第一個任務執行完並釋放鎖后才可以訪問。這是一個並發問題而且它將可能導致程序的並發機制失效。有一個更好的方式來處理這個問題:

  1) 打開數據庫連接

  2) 執行查詢  

  3) 使用從數據庫查詢到的50,000 行數據填充DataSet對象

  4) 鎖住全局DataSet 對象

  5) 設置本地數據庫為全局數據集 (DSGlobal = DSLocal)

  6)  解鎖DataSet 對象

  在這種情況下,除非我們需要更新DataSet對象否則我們不鎖住它,這樣就可以減小鎖在全局對象維持的時間。

  3. 執行一個任務依賴其他任務嗎?

  例如,你定義的任務可能是查詢數據庫並在一個DataGrid 控件中顯示數據。你可以將查詢數據庫作為第一個任務,將在DataGrid 中顯示數據作為第二個任務。第二個任務會在第一個任務完成后執行。因此,將查詢數據與顯示數據拆分開來並不是一個好的選項。一個折中的方法是讓第一個任務在完成時觸發一個事件,當事件發生后生成一個新線程。對應的,你可以使用一個定時器來通過一個公有屬性檢查是否完成,並繼續執行線程當它完成后。

下一篇介紹線程及線程間的關系…


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM