Antworten:
Das COM-Threading-Modell wird als "Apartment" -Modell bezeichnet, bei dem der Ausführungskontext initialisierter COM-Objekte entweder einem einzelnen Thread (Single Thread Apartment) oder mehreren Threads (Multi Thread Apartment) zugeordnet ist. In diesem Modell ist ein COM-Objekt, das einmal in einer Wohnung initialisiert wurde, für die Dauer seiner Laufzeit Teil dieser Wohnung.
Das STA-Modell wird für COM-Objekte verwendet, die nicht threadsicher sind. Das heißt, sie übernehmen keine eigene Synchronisation. Eine häufige Verwendung davon ist eine UI-Komponente. Wenn also ein anderer Thread mit dem Objekt interagieren muss (z. B. das Drücken einer Schaltfläche in einem Formular), wird die Nachricht auf den STA-Thread übertragen. Das Windows Forms Message Pumping System ist ein Beispiel dafür.
Wenn das COM-Objekt seine eigene Synchronisation verarbeiten kann, kann das MTA-Modell verwendet werden, bei dem mehrere Threads ohne Marshalling-Aufrufe mit dem Objekt interagieren dürfen.
Es kommt darauf an, wie Anrufe an Objekte behandelt werden und wie viel Schutz sie benötigen. COM-Objekte können die Laufzeit auffordern, sie davor zu schützen, von mehreren Threads gleichzeitig aufgerufen zu werden. diejenigen, die dies nicht können, können möglicherweise gleichzeitig von verschiedenen Threads aus aufgerufen werden, sodass sie ihre eigenen Daten schützen müssen.
Darüber hinaus muss die Laufzeit verhindern, dass ein COM-Objektaufruf die Benutzeroberfläche blockiert, wenn ein Aufruf von einem Benutzeroberflächenthread erfolgt.
Eine Wohnung ist ein Ort, an dem Objekte leben können, und sie enthalten einen oder mehrere Fäden. Die Wohnung definiert, was passiert, wenn Anrufe getätigt werden. Anrufe an Objekte in einer Wohnung werden in jedem Thread in dieser Wohnung empfangen und verarbeitet, mit der Ausnahme, dass ein Anruf eines Threads, der sich bereits in der richtigen Wohnung befindet, von selbst verarbeitet wird (dh ein direkter Anruf an das Objekt).
Threads können entweder in einem Single-Threaded-Apartment (in diesem Fall sind sie das einzige Thread in diesem Apartment) oder in einem Multi-Threaded-Apartment sein. Sie geben an, welche, wenn der Thread COM für diesen Thread initialisiert.
Die STA dient in erster Linie der Kompatibilität mit der Benutzeroberfläche, die an einen bestimmten Thread gebunden ist. Eine STA empfängt Benachrichtigungen über zu verarbeitende Anrufe, indem sie eine Fenstermeldung an ein verstecktes Fenster empfängt. Wenn ein ausgehender Anruf getätigt wird, wird eine modale Nachrichtenschleife gestartet, um zu verhindern, dass andere Fensternachrichten verarbeitet werden. Sie können einen Nachrichtenfilter angeben, der aufgerufen werden soll, damit Ihre Anwendung auf andere Nachrichten antworten kann.
Im Gegensatz dazu teilen sich alle MTA-Threads einen einzigen MTA für den Prozess. COM kann einen neuen Arbeitsthread starten, um einen eingehenden Anruf zu verarbeiten, wenn keine Threads verfügbar sind, bis zu einem Poollimit. Threads, die ausgehende Anrufe tätigen, blockieren einfach.
Der Einfachheit halber werden nur in DLLs implementierte Objekte betrachtet, die in der Registrierung angeben, was sie unterstützen, indem der ThreadingModel
Wert für den Schlüssel ihrer Klasse festgelegt wird. Es gibt vier Möglichkeiten:
ThreadingModel
Wert nicht vorhanden). Das Objekt wird im Haupt-UI-Thread des Hosts erstellt, und alle Aufrufe werden an diesen Thread weitergeleitet. Die Klassenfactory wird nur für diesen Thread aufgerufen.Apartment
. Dies zeigt an, dass die Klasse auf jedem Thread mit einem Thread ausgeführt werden kann. Wenn der Thread, der es erstellt, ein STA-Thread ist, wird das Objekt auf diesem Thread ausgeführt, andernfalls wird es in der Haupt-STA erstellt. Wenn keine Haupt-STA vorhanden ist, wird ein STA-Thread dafür erstellt. (Dies bedeutet, dass MTA-Threads, die Apartment-Objekte erstellen, alle Aufrufe eines anderen Threads zusammenstellen.) Die Klassenfactory kann von mehreren STA-Threads gleichzeitig aufgerufen werden, sodass ihre internen Daten davor geschützt werden müssen.Free
. Dies zeigt eine Klasse an, die für die Ausführung im MTA ausgelegt ist. Es wird immer in den MTA geladen, auch wenn es von einem STA-Thread erstellt wurde, was wiederum bedeutet, dass die Aufrufe des STA-Threads gemarshallt werden. Dies liegt daran, dass ein Free
Objekt im Allgemeinen mit der Erwartung geschrieben wird, dass es blockieren kann.Both
. Diese Klassen sind flexibel und werden in jede Wohnung geladen, aus der sie erstellt wurden. Sie müssen jedoch so geschrieben sein, dass sie beiden Anforderungen entsprechen: Sie müssen ihren internen Status vor gleichzeitigen Aufrufen schützen, falls sie in den MTA geladen werden, dürfen jedoch nicht blockieren, falls sie in eine STA geladen werden.Verwenden Sie [STAThread]
in .NET Framework grundsätzlich nur einen Thread, der eine Benutzeroberfläche erstellt. Worker-Threads sollten den MTA verwenden, es sei denn, sie verwenden Apartment
COM-Komponenten mit Markierungen. In diesem Fall sollten Sie die STA verwenden, um Probleme beim Marshalling von Overhead und Skalierbarkeit zu vermeiden, wenn dieselbe Komponente von mehreren Threads aufgerufen wird (da jeder Thread warten muss die Komponente wiederum). Es ist viel einfacher, wenn Sie ein separates COM-Objekt pro Thread verwenden, unabhängig davon, ob sich die Komponente in der STA oder im MTA befindet.
Ich finde die vorhandenen Erklärungen zu verschlungen. Hier ist meine Erklärung in einfachem Englisch:
STA: Wenn ein Thread ein COM-Objekt erstellt, das auf STA gesetzt ist (beim Aufrufen von CoCreateXXX können Sie ein Flag übergeben, das das COM-Objekt in den STA-Modus setzt), kann nur dieser Thread auf dieses COM-Objekt zugreifen (was STA bedeutet - Single Threaded Apartment) ) wird ein anderer Thread, der versucht, Methoden für dieses COM-Objekt aufzurufen, unter der Haube stillschweigend dazu gebracht, Nachrichten an den Thread zu senden, der das COM-Objekt erstellt (besitzt). Dies ähnelt stark der Tatsache, dass nur der Thread, der ein UI-Steuerelement erstellt hat, direkt darauf zugreifen kann. Und dieser Mechanismus soll komplizierte Sperr- / Entsperrvorgänge verhindern.
MTA: Wenn ein Thread ein COM-Objekt erstellt, das auf MTA festgelegt ist, kann so ziemlich jeder Thread direkt Methoden darauf aufrufen.
Das ist so ziemlich das Wesentliche. Obwohl es technisch gesehen einige Details gibt, die ich nicht erwähnt habe, wie im 'STA'-Absatz, muss der Ersteller-Thread selbst STA sein. Aber das ist so ziemlich alles, was Sie wissen müssen, um STA / MTA / NA zu verstehen.
STA (Single Threaded Apartment) ist im Grunde das Konzept, dass jeweils nur ein Thread mit Ihrem Code interagiert. Anrufe in Ihre Wohnung werden über Windows-Nachrichten (über ein nicht sichtbares Fenster) gemarshallt. Auf diese Weise können Anrufe in die Warteschlange gestellt und auf den Abschluss von Vorgängen gewartet werden.
In MTA (Multi Threaded Apartment) können viele Threads gleichzeitig ausgeführt werden, und Sie als Entwickler müssen die Thread-Sicherheit übernehmen.
Es gibt noch viel mehr über Threading-Modelle in COM zu lernen, aber wenn Sie Probleme haben zu verstehen, was sie sind, würde ich sagen, dass das Verständnis, was die STA ist und wie sie funktioniert, der beste Ausgangspunkt wäre, da die meisten COM-Objekte STAs sind.
Apartment-Threads Wenn sich ein Thread in derselben Wohnung befindet wie das Objekt, das er verwendet, handelt es sich um einen Apartment-Thread. Ich denke, dies ist nur ein COM-Konzept, da es nur eine Möglichkeit ist, über die Objekte und Threads zu sprechen, mit denen sie interagieren.
Jede EXE, die COM- oder OLE-Steuerelemente hostet, definiert ihren Apartmentstatus. Der Apartmentstatus ist standardmäßig STA (und für die meisten Programme sollte STA sein).
STA - Alle OLE-Steuerungen müssen notwendigerweise in einer STA leben. STA bedeutet, dass Ihr COM-Objekt immer im UI-Thread bearbeitet werden muss und nicht an andere Threads übergeben werden kann (ähnlich wie bei jedem UI-Element in MFC). Ihr Programm kann jedoch immer noch viele Threads haben.
MTA - Sie können das COM-Objekt in jedem Thread Ihres Programms bearbeiten.
Nach meinem Verständnis wird das 'Apartment' verwendet, um die COM-Objekte vor Multithreading-Problemen zu schützen.
Wenn ein COM-Objekt nicht threadsicher ist, sollte es als STA-Objekt deklariert werden. Dann kann nur der Thread, der es erstellt, darauf zugreifen. Der Erstellungs-Thread sollte sich selbst als STA-Thread deklarieren. Unter der Haube speichert der Thread die STA-Informationen in seinem TLS (Thread Local Storage). Wir nennen dieses Verhalten, dass der Thread eine STA-Wohnung betritt. Wenn andere Threads auf dieses COM-Objekt zugreifen möchten, sollte es den Zugriff auf den Erstellungsthread verwalten. Grundsätzlich verwendet der Erstellungsthread den Nachrichtenmechanismus, um die eingehenden Aufrufe zu verarbeiten.
Wenn ein COM-Objekt threadsicher ist, sollte es es als MTA-Objekt deklarieren. Auf das MTA-Objekt kann von mehreren Threads zugegriffen werden.
Code, der COM-Objekt-DLLs aufruft (zum Beispiel zum Lesen proprietärer Datendateien), funktioniert möglicherweise gut in einer Benutzeroberfläche, hängt jedoch auf mysteriöse Weise von einem Dienst ab. Der Grund dafür ist, dass ab .NET 2.0-Benutzeroberflächen STA (threadsicher) vorausgesetzt wird, während Dienste MTA annehmen ((zuvor haben Dienste STA angenommen). Das Erstellen eines STA-Threads für jeden COM-Aufruf in einem Dienst kann einen erheblichen Overhead verursachen.