ApartmentState für Dummies


118

Ich habe gerade einen Fehler behoben:

_Thread.SetApartmentState(ApartmentState.STA);

Jetzt möchte ich verstehen, was es bedeutet und warum es funktioniert!


1
Dieser Beitrag kann Ihnen helfen
Arsen Mkrtchyan

Antworten:


234

COM ist der Großvater von .NET. Sie hatten ziemlich hohe Ziele damit. Eines der Dinge, die COM tut, aber .NET vollständig überspringt, ist das Bereitstellen von Threading-Garantien für eine Klasse. Eine COM-Klasse kann veröffentlichen, welche Art von Threading-Anforderungen sie hat. Und die COM-Infrastruktur stellt sicher, dass diese Anforderungen erfüllt werden.

Dies fehlt in .NET vollständig. Sie können ein Queue <> -Objekt beispielsweise in mehreren Threads verwenden. Wenn Sie jedoch nicht ordnungsgemäß sperren, tritt in Ihrem Code ein böser Fehler auf, der sehr schwer zu diagnostizieren ist.

Die genauen Details des COM-Threadings sind zu groß, um in einen Beitrag zu passen. Ich werde mich auf die Einzelheiten Ihrer Frage konzentrieren. Ein Thread, der COM-Objekte erstellt, muss COM mitteilen, welche Unterstützung er COM-Klassen mit eingeschränkten Threading-Optionen gewähren möchte. Die überwiegende Mehrheit dieser Klassen unterstützt nur das sogenannte Apartment-Threading. Ihre Schnittstellenmethoden können nur sicher von demselben Thread aufgerufen werden, der die Instanz erstellt hat. Mit anderen Worten, sie verkünden "Ich unterstütze das Threading überhaupt nicht, bitte pass auf, dass du mich nie vom falschen Thread aus anrufst". Selbst wenn der Client - Code eigentlich nicht nennt es von einem anderen Thread.

Es gibt zwei Arten, STA (Single Threaded Apartment) und MTA. Es wird im Aufruf von CoInitializeEx () angegeben, einer Funktion, die von jedem Thread aufgerufen werden muss, der etwas mit COM tut. Die CLR führt diesen Aufruf automatisch durch, wenn ein Thread gestartet wird. Für den Hauptstart-Thread Ihres Programms erhält er den Wert, der vom Attribut [STAThread] oder [MTAThread] Ihrer Main () -Methode übergeben werden soll. Standard ist MTA. Für Threads, die Sie selbst erstellen, wird dies durch Ihren Aufruf von SetApartmentState () bestimmt. Standard ist MTA. Threadpool-Threads sind immer MTA, die nicht geändert werden können.

In Windows gibt es viel Code, für den eine STA erforderlich ist. Bemerkenswerte Beispiele, die Sie selbst verwenden würden, sind die Zwischenablage, Drag + Drop und die Shell-Dialoge (wie OpenFileDialog). Und eine Menge Code, den Sie nicht sehen können, wie UI-Automatisierungsprogramme und Hooks zum Beobachten von Nachrichten. Keiner dieser Codes muss threadsicher sein. Der Autor würde es sehr schwer haben, ihn sicher zu machen, ohne zu wissen, in welchem ​​Programm er verwendet wird. Dementsprechend muss der UI-Thread eines WPF- oder Windows Forms-Projekts immer STA sein, um diesen Code zu unterstützen, ebenso wie jeder Thread, der ein Fenster erstellt.

Das Versprechen, das Sie COM geben, dass Ihr Thread STA ist, erfordert jedoch , dass Sie den Single-Thread-Wohnungsvertrag befolgen. Sie sind ziemlich steif und es kann schwierig werden, Probleme zu diagnostizieren, wenn Sie den Vertrag brechen. Voraussetzungen sind, dass Sie den Thread niemals für längere Zeit blockieren und eine Nachrichtenschleife pumpen. Die letztere Anforderung wird von einem WPF- oder Winforms-UI-Thread erfüllt, aber Sie müssen sich selbst darum kümmern, wenn Sie Ihren eigenen STA-Thread erstellen. Die übliche Diagnose für Vertragsbruch ist Deadlock.

In der CLR ist eine Menge Unterstützung integriert, um diese Anforderungen zu erfüllen und Ihnen dabei zu helfen, Probleme zu vermeiden. Die Methoden lock statement und WaitOne () pumpen eine Nachrichtenschleife, wenn sie in einem STA-Thread blockiert werden. Dies kümmert sich jedoch nur um die Never-Block-Anforderung. Sie müssen dennoch eine eigene Nachrichtenschleife erstellen. Application.Run () in WPF und Winforms.

Ich habe zuvor eine Antwort beigesteuert, die weitere Details zur Bedeutung einer Nachrichtenschleife enthält, um COM bei Laune zu halten. Den Beitrag finden Sie hier .


3
Hervorragende Antwort! Der Fehler, den ich behoben habe, betraf einen Thread, den ich für einen langjährigen Berichtsersteller erstellt habe, der WPF-Steuerelemente zum Erstellen von Teilen des Berichts verwendet hat. Dies ist also sinnvoll, obwohl mir nicht bekannt ist, dass dieser Thread eine Nachrichtenschleife enthält .
Benjol

3
Ich musste den MSDN-Beitrag mehrmals ernsthaft lesen, um ihn zu verstehen. Ihre Antwort ist sehr klar und gut geschrieben. Danke dir!
ak3nat0n
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.