最近看了一些多線程方面的咚咚,說說自己的認識,拋磚引玉。
參考資料:
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 下查看到該COM的線程模式。如果該值是Apartment,則說明該COM只能以STA模式運行。其他的值有Free(MTA),Both(STA+MTA),Single(只能在一個單一的線程中執行)。
其他情況下,我們應該使用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線程為需要維護內部隱藏的視窗類別和訊息佇列而增加的。
下面是實現方法:
1private void CopyImages()
2 {
3 Word.Application app = null;
4 Word.Document doc = null;
5
6 app = new ApplicationClass();
7
8 try
9 {
10 object fileName = @"E:\A.doc";
11 doc = app.Documents.Open(ref fileName,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,
12 ref missing,ref missing,ref missing,ref missing,ref missing,ref missing);
13
14 int count = doc.InlineShapes.Count;
15 for(int i=1;i<=count;i++)
16 {
17 doc.InlineShapes[i].Range.Copy();
18
19 if (Clipboard.GetDataObject() != null)
20 {
21 IDataObject data = Clipboard.GetDataObject();
22
23 if (data.GetDataPresent(DataFormats.Bitmap))
24 {
25 Image image = (Image)data.GetData(DataFormats.Bitmap,true);
26 image.Save("E:\\" + i.ToString() + ".jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
27 }
28 else
29 {
30 lst_Items.Items.Add(doc.Name + ";無正確圖片資料");
31 }
32 }
33 else
34 {
35 lst_Items.Items.Add(doc.Name + ";粘貼板為空白");
36 }
37 }
38
39 }
40 catch(Exception ex)
41 {
42 lst_Items.Items.Add(doc.Name + "發生錯誤;" + ex.Message);
43 }
44 finally
45 {
46 if (doc != null)
47 doc.Close(ref missing,ref missing,ref missing);
48 if (app != null)
49 app.Quit(ref missing,ref missing,ref missing);
50 }