Single-Threaded Wohnungen
Die Verwendung von Singlethread-Wohnungen (der Apartmentmodellprozess) bietet ein nachrichtenbasiertes Paradigma für den Umgang mit mehreren Objekten, die gleichzeitig ausgeführt werden. Es ermöglicht Ihnen, effizienteren Code zu schreiben, indem Sie einen Thread zulassen, während es auf einen zeitaufwendigen Vorgang wartet, um eine weitere Threadausführung zu ermöglichen.
Jeder Thread in einem Prozess, der als Apartmentmodellprozess initialisiert wird und Fensternachrichten abruft und verteilt, ist ein Singlethread-Apartmentthread. Jeder Thread lebt in einer eigenen Wohnung. Innerhalb einer Wohnung können Schnittstellenzeiger ohne Marshalling übergeben werden, und daher kommunizieren alle Objekte in einem Singlethread-Apartmentthread direkt.
Eine logische Gruppierung verwandter Objekte, die alle im selben Thread ausgeführt werden und daher über eine synchrone Ausführung verfügen müssen, könnte sich im selben Singlethread-Apartmentthread befinden. Ein Apartmentmodellobjekt kann sich jedoch nicht in mehr als einem Thread befinden. Aufrufe von Objekten in anderen Threads müssen im Kontext des eigenen Threads erfolgen, sodass verteilte COM-Threads automatisch bei einem Aufruf eines Proxys ausgeführt werden.
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 Marshallingmodell, das Objekte in verschiedenen Prozessen verwenden, um Zeiger über Prozessgrenzen hinweg zu übergeben. Indem Sie einen Zeiger auf das standardmäßige Marshaling-Objekt abrufen, können Sie Schnittstellenzeiger über Threadgrenzen hinweg (zwischen Wohnungen) auf die gleiche Weise wie zwischen Prozessen marshallen. (Schnittstellenzeiger müssen gemarstet werden, wenn sie zwischen Wohnungen übergeben werden.)
Regeln für Singlethread-Wohnungen sind einfach, aber es ist wichtig, sie sorgfältig zu befolgen:
- Jedes Objekt sollte nur auf einem Thread (innerhalb einer Singlethread-Wohnung) leben.
- Initialisieren Sie die COM-Bibliothek für jeden Thread.
- Marshal alle Zeiger auf Objekte, wenn sie zwischen Wohnungen übergeben werden.
- Jede Einzelthread-Wohnung muss über eine Nachrichtenschleife verfügen, um Anrufe von anderen Prozessen und Wohnungen innerhalb desselben Prozesses zu verarbeiten. Singlethread-Apartments ohne Objekte (nur Client) benötigen auch eine Nachrichtenschleife, um die Von einigen Anwendungen verwendeten Broadcast-Nachrichten zu verteilen.
- DLL-basierte oder prozessinterne Objekte rufen die COM-Initialisierungsfunktionen nicht auf; Stattdessen registrieren sie ihr Threadingmodell mit dem ThreadingModel benannten Wert unter dem InprocServer32 Schlüssel in der Registrierung. Apartmentfähige Objekte müssen auch DLL-Einstiegspunkte sorgfältig schreiben. Es gibt besondere Aspekte, die für Threading-In-Process-Server gelten. Weitere Informationen finden Sie unter In-Process Serverthreading-Probleme.
Während mehrere Objekte in einem einzelnen Thread leben können, kann kein Apartmentmodellobjekt auf 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. Die Hauptwohnung ist der Thread, der zuerst CoInitializeEx aufruft. Informationen zu In-Process-Servern finden Sie unter In-Process Serverthreading-Probleme.
Alle Aufrufe an ein Objekt müssen an seinem Thread (innerhalb seiner Wohnung) erfolgen. Es ist verboten, ein Objekt direkt aus einem anderen Thread aufzurufen; Die Verwendung von Objekten auf diese freithreadierte Weise kann zu Problemen für Anwendungen führen. Die Auswirkung dieser Regel besteht darin, dass alle Zeiger auf Objekte gemarstet werden müssen, wenn sie zwischen Wohnungen übergeben werden. COM stellt die folgenden beiden Funktionen für diesen Zweck bereit:
- CoMarshalInterThreadInterfaceInStream eine Schnittstelle in ein Streamobjekt marshallt, das an den Aufrufer zurückgegeben wird.
- CoGetInterfaceAndReleaseStream einen Schnittstellenzeiger aus einem Streamobjekt entmarstet und loslässt.
Diese Funktionen umschließen Aufrufe an CoMarshalInterface und CoUnmarshalInterface Funktionen, die die Verwendung der MSHCTX_INPROC-Kennzeichnung erfordern.
Im Allgemeinen wird das Marshalling automatisch von COM durchgeführt. Wenn Sie z. B. einen Schnittstellenzeiger als Parameter in einem Methodenaufruf für ein Objekt in einem anderen Apartment an ein Objekt übergeben oder CoCreateInstanceaufrufen, führt COM die Marshaling automatisch durch. In einigen speziellen Fällen, in denen der Anwendungsschreiber Schnittstellenzeiger zwischen Wohnungen übergibt, ohne die normalen COM-Mechanismen zu verwenden, muss der Autor die Marshalling manuell verarbeiten.
Wenn eine Wohnung (Apartment 1) in einem Prozess einen Schnittstellenzeiger hat und eine andere Wohnung (Apartment 2) seine Verwendung erfordert, muss Apartment 1 CoMarshalInterThreadInterfaceInStream aufrufen, um die Schnittstelle zu marshallen. Der von dieser Funktion erstellte Datenstrom ist threadsicher und muss in einer Variablen gespeichert werden, die von Apartment 2 zugänglich ist. Apartment 2 muss diesen Datenstrom an CoGetInterfaceAndReleaseStream übergeben, um die Schnittstelle zu entmarsen und einen Zeiger auf einen Proxy zurückzugeben, über den sie auf die Schnittstelle zugreifen kann. Die Hauptwohnung muss lebendig bleiben, bis der Client alle COM-Arbeiten abgeschlossen hat (da einige prozessinterne Objekte in der Hauptwohnung geladen werden, wie in In-Process Serverthreading-Problemebeschrieben). Nachdem ein Objekt auf diese Weise zwischen Threads übergeben wurde, ist es sehr einfach, Schnittstellenzeiger als Parameter zu übergeben. Auf diese Weise führt verteiltes COM den Marshalling- und Threadwechsel für die Anwendung durch.
Um Anrufe von anderen Prozessen und Wohnungen innerhalb desselben Prozesses zu verarbeiten, muss jedes Singlethread-Apartment eine Nachrichtenschleife aufweisen. Dies bedeutet, dass die Arbeitsfunktion des Threads über eine GetMessage/DispatchMessage-Schleife verfügen muss. Wenn andere Synchronisierungsgrundtypen für die Kommunikation zwischen Threads verwendet werden, kann die MsgWaitForMultipleObjects--Funktion verwendet werden, um sowohl auf Nachrichten als auch auf Threadsynchronisierungsereignisse zu warten. Die Dokumentation für diese Funktion weist ein Beispiel für diese Art von Kombinationsschleife auf.
COM erstellt ein ausgeblendetes Fenster mit der Windows-Klasse "OleMainThreadWndClass" in jedem Singlethread-Apartment. Ein Aufruf eines Objekts wird als Fenstermeldung für dieses ausgeblendete Fenster empfangen. Wenn die Wohnung des Objekts die Nachricht abruft und sendet, empfängt das ausgeblendete Fenster sie. Die Fensterprozedur ruft dann die entsprechende Schnittstellenmethode des Objekts auf.
Wenn mehrere Clients ein Objekt aufrufen, werden die Anrufe in der Nachrichtenwarteschlange in die Warteschlange eingereiht, und das Objekt erhält jedes Mal einen Anruf, wenn seine Wohnung Nachrichten abruft und verteilt. Da die Aufrufe von COM synchronisiert werden und die Aufrufe immer vom Thread übermittelt werden, der zur Wohnung des Objekts gehört, müssen die Schnittstellenimplementierungen des Objekts keine Synchronisierung bereitstellen. Singlethread-Apartments können IMessageFilter- implementieren, damit sie bei Bedarf Anrufe abbrechen oder Fensternachrichten empfangen können.
Das Objekt kann erneut ausgeführt werden, wenn eine seiner Schnittstellenmethodenimplementierungen Nachrichten abruft und sendet oder einen ORPC-Aufruf an einen anderen Thread sendet, wodurch ein anderer Aufruf an das Objekt (von derselben Wohnung) übermittelt wird. OLE verhindert nicht die Reentranz auf demselben Thread, kann aber dazu beitragen, Threadsicherheit bereitzustellen. Dies ist identisch mit der Art und Weise, wie eine Fensterprozedur erneut ausgeführt werden kann, wenn sie Nachrichten abruft und versendet, während eine Nachricht verarbeitet wird. Das Aufrufen eines out-of-process SingleThread-Apartmentservers, der einen anderen Singlethread-Apartmentserver aufruft, ermöglicht jedoch, dass der erste Server erneut eingeteilt wird.
Verwandte Themen