Multithread-Wohnungen
In einem Multithread-Apartmentmodell befinden sich alle Threads im Prozess, die als Freithread initialisiert wurden, in einem einzelnen Apartment. Daher ist es nicht erforderlich, zwischen Threads zu marshallen. Die Threads müssen keine Nachrichten abrufen und senden, da COM in diesem Modell keine Fenstermeldungen verwendet.
Aufrufe von -Methoden von -Objekten im Multithread-Apartment können für jeden Thread im Apartment ausgeführt werden. Es gibt keine Serialisierung von Aufrufen; Viele Aufrufe können gleichzeitig an dieselbe Methode oder an dasselbe Objekt erfolgen. Objekte, die in der Multithread-Wohnung erstellt werden, müssen jederzeit Aufrufe ihrer Methoden von anderen Threads verarbeiten können.
Da Aufrufe von Objekten in keiner Weise serialisiert werden, bietet multithreaded object concurrency die höchste Leistung und nutzt den besten Vorteil der Multiprozessorhardware für threadübergreifende, prozessübergreifende und computerübergreifende Aufrufe. Dies bedeutet jedoch, dass der Code für Objekte die Synchronisierung in ihren Schnittstellenimplementierungen bereitstellen muss, in der Regel durch die Verwendung von Synchronisierungsgrundtypen wie Ereignisobjekten, kritischen Abschnitten, Mutexen oder Semaphoren, die weiter unten in diesem Abschnitt beschrieben werden. Da das Objekt die Lebensdauer der Threads, die darauf zugreifen, nicht steuert, kann außerdem kein threadspezifischer Zustand im Objekt (im lokalen Threadspeicher) gespeichert werden.
Im Folgenden finden Sie einige wichtige Überlegungen zur Synchronisierung für Multithread-Wohnungen:
- COM stellt die Anrufsynchronisierung nur für Singlethread-Wohnungen bereit.
- Multithread-Wohnungen empfangen keine Anrufe, während Sie Anrufe tätigen (im selben Thread).
- Multithread-Apartments können keine eingabesynchronen Anrufe tätigen.
- Asynchrone Aufrufe werden in synchrone Aufrufe in Multithread-Apartments konvertiert.
- Der Nachrichtenfilter wird für keinen Thread in einem Multithread-Apartment aufgerufen.
Um einen Thread als Freethread zu initialisieren, rufen Sie CoInitializeEx auf, und geben Sie COINIT_MULTITHREADED an. Informationen zum In-Process-Serverthreading finden Sie unter Probleme beim In-Process-Serverthreading.
Mehrere Clients können gleichzeitig aus verschiedenen Threads ein Objekt aufrufen, das Freethreading unterstützt. Auf Out-of-Process-Servern mit Freethread erstellt COM über das RPC-Subsystem einen Pool von Threads im Serverprozess, und ein Clientaufruf (oder mehrere Clientaufrufe) kann jederzeit von einem dieser Threads übermittelt werden. Ein Out-of-Process-Server muss auch die Synchronisierung in seiner Klassenfactory implementieren. Freithreadobjekte in Prozessen können direkte Aufrufe von mehreren Threads des Clients empfangen.
Der Client kann COM-Arbeit in mehreren Threads ausführen. Alle Threads gehören zur gleichen Multithread-Wohnung. Schnittstellenzeiger werden innerhalb eines Multithread-Apartments direkt von Thread zu Thread übergeben, sodass Schnittstellenzeiger nicht zwischen den Threads gemarshallt werden. Nachrichtenfilter (Implementierungen von IMessageFilter) werden in Multithread-Apartments nicht verwendet. Der Clientthread wird angehalten, wenn er einen COM-Aufruf an Objekte außerhalb der Wohnung sendet, und wird fortgesetzt, wenn der Aufruf zurückgegeben wird. Aufrufe zwischen Prozessen werden weiterhin von RPC verarbeitet.
Threads, die mit dem Freethread-Modell initialisiert wurden, müssen eine eigene Synchronisierung implementieren. Wie bereits in diesem Abschnitt erwähnt, aktiviert Windows diese Implementierung über die folgenden Synchronisierungsgrundtypen:
- Ereignisobjekte bieten eine Möglichkeit, einen oder mehrere Threads zu signalisieren, dass ein Ereignis aufgetreten ist. Jeder Thread innerhalb eines Prozesses kann ein Ereignisobjekt erstellen. Ein Handle für das Ereignis wird von der Ereigniserstellungsfunktion CreateEvent zurückgegeben. Nachdem ein Ereignisobjekt erstellt wurde, können Threads mit einem Handle für das Objekt darauf warten, bevor die Ausführung fortgesetzt wird.
- Kritische Abschnitte werden für einen Codeabschnitt verwendet, der exklusiven Zugriff auf einen Satz freigegebener Daten erfordert, bevor er ausgeführt werden kann, und der nur von den Threads innerhalb eines einzelnen Prozesses verwendet wird. Ein kritischer Abschnitt ist wie ein Drehkreuz, durch das jeweils nur ein Thread durchlaufen kann, und funktioniert wie folgt:
- Um sicherzustellen, dass nicht mehr als ein Thread gleichzeitig auf freigegebene Daten zugreift, ordnet der primäre Thread eines Prozesses eine globale CRITICAL_SECTION Datenstruktur zu und initialisiert deren Member. Ein Thread, der in einen kritischen Abschnitt eintritt, ruft die EnterCriticalSection-Funktion auf und ändert die Member der Datenstruktur.
- Ein Thread, der versucht, in einen kritischen Abschnitt zu gelangen, ruft EnterCriticalSection auf, das überprüft, ob die CRITICAL_SECTION Datenstruktur geändert wurde. Wenn dies der Grund ist, befindet sich derzeit ein anderer Thread im kritischen Abschnitt, und der nachfolgende Thread wird in den Standbymodus versetzt. Ein Thread, der einen kritischen Abschnitt verlässt, ruft LeaveCriticalSection auf, wodurch die Datenstruktur zurückgesetzt wird. Wenn ein Thread einen kritischen Abschnitt verlässt, aktiviert das System einen der Ruhethreads, der dann in den kritischen Abschnitt wechselt.
- Mutexes führt dieselbe Funktion wie ein kritischer Abschnitt aus, mit der Ausnahme, dass der Mutex für Threads zugänglich ist, die in verschiedenen Prozessen ausgeführt werden. Der Besitz eines Mutex-Objekts ist so, als hätte man das Wort in einer Debatte. Ein Prozess erstellt ein Mutex-Objekt, indem die CreateMutex-Funktion aufgerufen wird, die ein Handle zurückgibt. Der erste Thread, der ein Mutex-Objekt anfordert, erhält den Besitz davon. Wenn der Thread mit dem Mutex fertig ist, wird der Besitz auf der Grundlage von First Come, First Served an andere Threads übergeben.
- Semaphore werden verwendet, um eine Verweisanzahl für einige verfügbare Ressourcen zu verwalten. Ein Thread erstellt einen Semaphor für eine Ressource, indem er die CreateSemaphore-Funktion aufruft und einen Zeiger auf die Ressource, eine anfängliche Ressourcenanzahl und die maximale Ressourcenanzahl übergibt. Diese Funktion gibt ein Handle zurück. Ein Thread, der eine Ressource anfordert, übergibt sein Semaphorhandle in einem Aufruf der WaitForSingleObject-Funktion . Das Semaphorobjekt fragt die Ressource ab, um zu bestimmen, ob sie verfügbar ist. Wenn ja, verringert das Semaphor die Ressourcenanzahl und reaktiviert den wartenden Thread. Wenn die Anzahl null ist, bleibt der Thread im Ruhezustand, bis ein anderer Thread eine Ressource freigibt, wodurch der Semaphor die Anzahl auf eins erhöht.
Zugehörige Themen