2010-11-11 85 views
88

我只是用這個修正了一個錯誤:的ApartmentState傻瓜

_Thread.SetApartmentState(ApartmentState.STA); 

現在我想明白這意味着什麼,以及爲什麼它的作品!

+1

[This](http://stackoverflow.com/questions/165316/stathread-and-multithreading)文章可以幫助您 – 2010-11-11 12:45:14

回答

178

COM是.NET的盛大父親。他們有很高的目標,COM做的事情之一,但是.NET完全跳過了這個目標,爲類提供了線程保證。一個COM類可以發佈它具有的線程要求。 COM基礎架構確保滿足這些要求。

這在.NET中完全沒有。例如,您可以在多個線程中使用隊列<>對象,但如果未正確鎖定,則代碼中會有一個非常難以診斷的惡意錯誤。

COM線程的確切詳細信息太大,不適合發佈。我將專注於您的問題的具體內容。創建COM對象的線程必須告訴COM對於具有受限線程選項的COM類給予什麼樣的支持。絕大多數這些類只支持所謂的Apartment線程,它們的接口方法只能從創建實例的相同線程安全地調用。換句話說,他們宣佈「我不支持線程,請注意永不從錯誤的線程呼叫我」。即使客戶端代碼實際上是確實從另一個線程調用它。

有兩種STA(單線程公寓)和MTA。它在CoInitializeEx()調用中指定,函數必須由任何對COM執行任何操作的線程調用。 CLR在啓動線程時自動進行該調用。對於程序的主啓動線程,它將獲得從Main()方法的[STAThread]或[MTAThread]屬性傳遞的值。默認是MTA。對於您自己創建的線程,由您對SetApartmentState()的調用確定。默認是MTA。線程池線程始終是MTA,無法更改。

Windows中有很多需要STA的代碼。值得注意的例子是剪貼板,拖放和外殼對話框(如OpenFileDialog)。 WPF或Windows窗體項目的UI線程應始終爲STA,就像創建窗口的任何線程一樣。

你做出的承諾,COM,你的線程是STA但確實需要你遵循單線程公寓的合同。他們非常僵硬,當你違約時你很難診斷麻煩。要求是你從來沒有阻塞任何時間的線程,你泵送一個消息循環。後者的要求通過WPF或Winforms的UI線程滿足,但如果您創建自己的STA線程,則需要自己處理。破壞合同的常見診斷是僵局。

CLR內置了相當多的支持來支持這些要求,幫助您擺脫困境。例如,語句會在STA線程上阻塞時抽取消息循環。大多數同步類也是如此,Mutex是一個明顯的例外。然而,這隻需要注意從不阻止的要求,您仍然需要創建自己的消息循環。 WPF和Winforms中的Application.Run()。

我以前提供了一個答案,其中包含了有關讓消息循環保持COM快樂的重要性的更多細節。你會發現post here

+2

優秀的答案!我解決的問題是我爲一個長時間運行的報表生成器創建的線程,該生成器使用WPF控件構建報表的各個部分,這樣纔有意義,儘管我不知道該線程上有一個消息循環。 – Benjol 2010-11-12 23:33:13

+1

我認真閱讀了MSDN文章多次瞭解它,你的答案非常清晰,寫得很好。謝謝! – ak3nat0n 2011-04-26 04:20:44

+4

這個迴應是徹底和真棒的。 – 2013-07-08 20:33:05