Single-Threaded Apartments
Die Verwendung von Singlethread-Apartments (der Apartmentmodellprozess) bietet ein nachrichtenbasiertes Paradigma für den Umgang mit mehreren gleichzeitig ausgeführten Objekten. Es ermöglicht Ihnen, effizienteren Code zu schreiben, indem ein Thread zugelassen wird, während er auf den Abschluss eines zeitaufwendigen Vorgangs wartet, um die Ausführung eines anderen Threads zu ermöglichen.
Jeder Thread in einem Prozess, der als Apartmentmodellprozess initialisiert wird und Fensternachrichten abruft und sendet, ist ein Singlethread-Apartmentthread. Jeder Thread lebt in seiner eigenen Wohnung. Innerhalb eines Apartments können Schnittstellenzeiger ohne Marshalling übergeben werden, und daher kommunizieren alle Objekte in einem Singlethread direkt.
Eine logische Gruppierung verwandter Objekte, die alle im selben Thread ausgeführt werden und daher synchron ausgeführt werden müssen, könnte im gleichen Singlethread-Apartmentthread ausgeführt werden. Ein Apartmentmodellobjekt darf sich jedoch nicht in mehr als einem Thread befinden. Aufrufe von Objekten in anderen Threads müssen innerhalb des Kontexts des besitzenden Threads erfolgen, sodass verteilte COM-Threads automatisch für Sie wechselt, wenn Sie einen Proxy aufrufen.
Die Interprocess- und Interthreadmodelle sind ähnlich. Wenn ein Schnittstellenzeiger an ein Objekt in einem anderen Apartment (in einem anderen Thread) innerhalb desselben Prozesses übergeben werden muss, verwenden Sie dasselbe Marshallmodell, das Objekte in verschiedenen Prozessen verwenden, um Zeiger über Prozessgrenzen hinweg zu übergeben. Wenn Sie einen Zeiger auf das Standard-Marshallobjekt erhalten, können Sie Schnittstellenzeiger über Threadgrenzen hinweg (zwischen Wohnungen) auf die gleiche Weise wie zwischen Prozessen marshallen. (Schnittstellenzeiger müssen gemarst werden, wenn sie zwischen Apartments übergeben werden.)
Regeln für Singlethread-Wohnungen sind einfach, aber es ist wichtig, sie sorgfältig zu befolgen:
- Jedes Objekt sollte nur in einem Thread (innerhalb eines Singlethread-Apartments) leben.
- Initialisieren Sie die COM-Bibliothek für jeden Thread.
- Marshallen Sie alle Zeiger auf Objekte, wenn Sie sie zwischen Wohnungen übergeben.
- Jedes Singlethread-Apartment muss über eine Nachrichtenschleife verfügen, um Anrufe von anderen Prozessen und Apartments innerhalb desselben Prozesses verarbeiten zu können. Singlethread-Apartments ohne Objekte (nur Client) benötigen auch eine Nachrichtenschleife, um die Broadcastnachrichten zu senden, die einige Anwendungen verwenden.
- DLL-basierte oder prozessinterne Objekte rufen die COM-Initialisierungsfunktionen nicht auf. stattdessen registrieren sie ihr Threadingmodell mit dem ThreadingModel named-value unter dem Schlüssel InprocServer32 in der Registrierung. Apartmentfähige Objekte müssen auch DLL-Einstiegspunkte sorgfältig schreiben. Es gibt besondere Überlegungen, die für Threading in Prozessservern gelten. Weitere Informationen finden Sie unter Probleme mit dem In-Process-Serverthreading.
Während mehrere Objekte in einem einzelnen Thread leben können, kann kein Apartmentmodellobjekt in mehr als einem Thread leben.
Jeder Thread eines Clientprozesses oder Out-of-Process-Servers muss CoInitialize aufrufen oder CoInitializeEx aufrufen und COINIT_APARTMENTTHREADED für den dwCoInit-Parameter angeben. Das Standard-Apartment ist der Thread, der Zuerst CoInitializeEx aufruft. Informationen zu prozessinternen Servern finden Sie unter Probleme beim In-Process-Serverthreading.
Alle Aufrufe eines Objekts müssen in seinem Thread (innerhalb seiner Wohnung) erfolgen. Es ist verboten, ein Objekt direkt aus einem anderen Thread aufzurufen. Die Verwendung von Objekten auf diese Weise mit Freethreads kann Probleme für Anwendungen verursachen. Die Implikation dieser Regel besteht darin, dass alle Zeiger auf Objekte gemarst werden müssen, wenn sie zwischen Apartments übergeben werden. COM stellt zu diesem Zweck die folgenden beiden Funktionen bereit:
- CoMarshalInterThreadInterfaceInStream marshallt eine Schnittstelle in ein Streamobjekt, das an den Aufrufer zurückgegeben wird.
- CoGetInterfaceAndReleaseStream hebt einen Schnittstellenzeiger aus einem Streamobjekt auf und gibt ihn frei.
Diese Funktionen umschließen Aufrufe der Funktionen CoMarshalInterface und CoUnmarshalInterface , die die Verwendung des MSHCTX_INPROC-Flags erfordern.
Im Allgemeinen erfolgt das Marshalling automatisch durch COM. Wenn Sie beispielsweise einen Schnittstellenzeiger als Parameter in einem Methodenaufruf an einen Proxy an ein Objekt in einem anderen Apartment übergeben oder CoCreateInstance aufrufen, führt COM das Marshalling automatisch durch. In einigen besonderen Fällen, in denen der Anwendungsschreiber Schnittstellenzeiger zwischen Wohnungen übergibt, ohne die normalen COM-Mechanismen zu verwenden, muss der Writer das Marshalling manuell verarbeiten.
Wenn eine Wohnung (Apartment 1) in einem Prozess einen Schnittstellenzeiger und ein anderes Apartment (Apartment 2) seine Verwendung erfordert, muss Apartment 1 CoMarshalInterThreadInterfaceInStream aufrufen, um die Schnittstelle zu marshallen. Der von dieser Funktion erstellte Stream ist threadsicher und muss in einer Variablen gespeichert werden, auf die apartment 2 zugegriffen werden kann. Apartment 2 muss diesen Stream an CoGetInterfaceAndReleaseStream übergeben, um die Schnittstelle aufzuheben, und erhält einen Zeiger auf einen Proxy, über den es auf die Schnittstelle zugreifen kann. Das Standard-Apartment muss am Leben bleiben, bis der Client alle COM-Arbeiten abgeschlossen hat (da einige prozessinterne Objekte in das Standard-Apartment geladen werden, wie in In-Process Server Threading Issues beschrieben). Nachdem ein Objekt auf diese Weise zwischen Threads übergeben wurde, ist es sehr einfach, Schnittstellenzeiger als Parameter zu übergeben. Auf diese Weise übernimmt verteiltes COM das Marshallen und Threadwechsel für die Anwendung.
Um Anrufe von anderen Prozessen und Apartments innerhalb desselben Prozesses zu verarbeiten, muss jedes Singlethread-Apartment über eine Nachrichtenschleife verfügen. Dies bedeutet, dass die Arbeitsfunktion des Threads über eine GetMessage/DispatchMessage-Schleife verfügen muss. Wenn für die Kommunikation zwischen Threads andere Synchronisierungsgrundtypen verwendet werden, kann die MsgWaitForMultipleObjects-Funktion verwendet werden, um sowohl auf Nachrichten als auch auf Threadsynchronisierungsereignisse zu warten. Die Dokumentation für diese Funktion enthält ein Beispiel für diese Art von Kombinationsschleife.
COM erstellt ein ausgeblendetes Fenster mithilfe der Windows-Klasse "OleMainThreadWndClass" in jedem Singlethreaded-Apartment. Ein Aufruf eines Objekts wird als Fenstermeldung für dieses ausgeblendete Fenster empfangen. Wenn das Apartment des Objekts die Nachricht abruft und sendet, empfängt sie das ausgeblendete Fenster. Die Fensterprozedur ruft dann die entsprechende Schnittstellenmethode des -Objekts auf.
Wenn mehrere Clients ein Objekt aufrufen, werden die Aufrufe in der Nachrichtenwarteschlange in die Warteschlange eingereiht, und das Objekt empfängt jedes Mal einen Aufruf, wenn sein Apartment Nachrichten abruft und sendet. Da die Aufrufe von COM synchronisiert werden und die Aufrufe immer von dem Thread übermittelt werden, der zum Apartment des Objekts gehört, müssen die Schnittstellenimplementierungen des Objekts keine Synchronisierung bereitstellen. Singlethread-Apartments können IMessageFilter implementieren, um bei Bedarf Anrufe abbrechen oder Fensternachrichten empfangen zu können.
Das -Objekt kann erneut aufgerufen werden, wenn eine seiner Schnittstellenmethodenimplementierungen Nachrichten abruft und sendet oder einen ORPC-Aufruf an einen anderen Thread ausgibt, wodurch ein weiterer Aufruf an das Objekt (durch dasselbe Apartment) übermittelt wird. OLE verhindert nicht die ErneuteIntrahierung für denselben Thread, kann jedoch zur Threadsicherheit beitragen. Dies ist identisch mit der Art und Weise, wie eine Fensterprozedur erneut aufgerufen werden kann, wenn sie beim Verarbeiten einer Nachricht Nachrichten abruft und sendet. Durch Das Aufrufen eines Out-of-Process-Singlethread-Apartmentservers, der einen anderen Singlethread-Apartmentserver aufruft, kann der erste Server jedoch erneut aufgerufen werden.
Zugehörige Themen