.NET的兩種執行緒模型:STA和MTA
參考資料:
http://www.yesky.com/20010207/158097.shtml
http://www.ftponline.com/china/XmlFile.aspx?ID=242
http://research.microsoft.com/~chadv/java_com2.htm
http://blogs.msdn.com/jfoscoding/archive/2005/04/07/406341.aspx
.NET支援兩種執行緒模型:STA和MTA。
STA(single threaded apartments)。apartment只是一個邏輯上的概念,它可以包含一個或多個執行緒。一個AppDomain可以包括一個或多個apartment。STA是指該apartment中只能包含一個thread。
MTA(multi threaded apartments)。指該apartment中可以包含多個thread。
STA and MTA 之間最大的區別就是MTA 可以在同一個apartment 中使用所有的共享資源併發執行多個執行緒。 而多個STA雖然可以共享資料,但是不能併發執行執行緒,存在效能問題。
執行緒的建立:
當建立一個新的STA執行緒時,CLR會在該AppDomain中建立一個apartment和thread(從屬於該apartment)。如果是建立MTA執行緒,則會CLR會檢查該AppDomain是否存在一個存放MTA的apartment,如果存在僅建立該執行緒到該MTA中,否則就建立一個MTA和thread(從屬於該apartment)。
我們可以設定執行緒的屬性。例如 t.ApartmentState = ApartmentState.STA;
執行緒的使用區別:
我們應該僅僅在訪問STA-based 的COM元件時才使用STA執行緒模式。可以在登錄檔的HKEY_CLASSES_ROOT\CLSID\{Class ID of the COM component} \InProcServer32
其他情況下,我們應該使用MTA的執行緒,雖然需要我們費心執行緒間資源的同步問題。
示例:
我現在想在一個windows form的程式中實現從某個word文件複製圖片並儲存的方案。
具體是:開啟word文件,將圖片資訊複製到貼上板中,然後從貼上板中取得圖片資訊,再儲存到本地目錄中。
說明:(本來是放在程式碼下面的,無奈POST之後就被程式碼擋住不顯示了)
如果在某個按鈕的事件中,直接呼叫該方法,那麼介面將變得沒有響應。所以我們需要考慮使用多執行緒來解決這個問題。Thread t = new Thread(new TheardStart(CopyImages); t.Start();
如果是這樣,則程式會發生錯誤.。要麼顯示出現異常,要麼沒異常但是Clipboard為空,取不到任何資料!為什麼呢?
因為Word.Application 是Automation並且STA-Based,不能在沒有指定ThreadApartment的執行緒中被呼叫。所以導致了各種錯誤,所以需要在t.Start();前面加上t.Apartment = ApartmentState.STA;這樣就完全正常了。
對於MTA的多執行緒我們就見的比較多了,不再舉例了。
另外一點不明白,我監視工作管理員發現,我在執行Thread t = new Thread(new TheardStart(CopyImages);t.Apartment = ApartmentState.STA; t.Start();之後該程式的程序中執行緒數從3個增加到6個,如果建立的是MTA的執行緒則只增加1。我的理解是STA執行緒為需要維護內部隱藏的視窗類和訊息佇列而增加的。
下面是實現方法:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using Microsoft.Office.Interop.Word;
- using System.Windows.Forms;
- using System.Drawing;
- namespace ConsoleApplication1
- {
- class STAANDMTA
- {
- static
- {
- Thread t = new Thread(new ThreadStart(CopyImages));
- t.ApartmentState = ApartmentState.STA;
- t.Start();
- }
- privatestaticvoid CopyImages()
- {
- Microsoft.Office.Interop.Word.Application app = null;
- Microsoft.Office.Interop.Word.Document doc = null;
- object missing = System.Reflection.Missing.Value;
- app = new Microsoft.Office.Interop.Word.Application();
- try
- {
- object fileName = @"E:\A.doc";
- doc = app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
- ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
- int count = doc.InlineShapes.Count;
- for (int i = 1; i <= count; i++)
- {
- doc.InlineShapes[i].Range.Copy();//複製到貼上板
- if (System.Windows.Forms.Clipboard.GetDataObject() != null)
- {
- IDataObject data = Clipboard.GetDataObject();
- if (data.GetDataPresent(DataFormats.Bitmap))
- {
- Image image = (Image)data.GetData(DataFormats.Bitmap, true);
- image.Save("E:\\" + i.ToString() + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
- }
- else
- {
- //lst_Items.Items.Add(doc.Name + ";無正確圖片資料");
- }
- }
- else
- {
- //lst_Items.Items.Add(doc.Name + ";貼上板為空");
- }
- }
- }
- catch (Exception ex)
- {
- //lst_Items.Items.Add(doc.Name + "發生錯誤;" + ex.Message);
- }
- finally
- {
- if (doc != null)
- doc.Close(ref missing, ref missing, ref missing);
- if (app != null)
- app.Quit(ref missing, ref missing, ref missing);
- }
- }
- }
- }