In-Process Serverthreadingprobleme
Ein Prozessserver ruft CoInitialize, CoInitializeEx oder OleInitialize nicht auf, um sein Threadingmodell zu markieren. Für threadfähige DLL-basierte oder prozessinterne Objekte müssen Sie das Threadingmodell in der Registrierung festlegen. Das Standardmodell, wenn Sie kein Threadingmodell angeben, ist Einzelthread pro Prozess. Um ein Modell anzugeben, fügen Sie dem Schlüssel InprocServer32 in der Registrierung den Wert ThreadingModel hinzu.
DLLs, die die Instanziierung eines Klassenobjekts unterstützen, müssen die Funktionen DllGetClassObject und DllCanUnloadNow implementieren und exportieren. Wenn ein Client eine instance der Klasse wünscht, die von der DLL unterstützt wird, ruft ein Aufruf von CoGetClassObject (entweder direkt oder über einen Aufruf von CoCreateInstance) DllGetClassObject auf, um einen Zeiger auf sein Klassenobjekt abzurufen, wenn das Objekt in einer DLL implementiert ist. DllGetClassObject sollte daher in der Lage sein, mehrere Klassenobjekte oder ein einzelnes threadsicheres Objekt zu verschenken (im Wesentlichen nur interlockedIncrement/InterlockedDecrement für ihre internen Verweisanzahlen).
Wie der Name schon sagt, wird DllCanUnloadNow aufgerufen, um zu bestimmen, ob die DLL, die sie implementiert, verwendet wird, sodass der Aufrufer sie sicher entladen kann, falls dies nicht der Fehler ist. Aufrufe von CoFreeUnusedLibraries von einem beliebigen Thread leiten immer über den Thread des Standard Apartments weiter, um DllCanUnloadNow aufzurufen.
Wie andere Server können prozessinterne Server Singlethreads, Apartmentthreads oder Freethreads sein. Diese Server können von jedem OLE-Client verwendet werden, unabhängig vom Threadingmodell, das von diesem Client verwendet wird.
Alle Kombinationen der Threadingmodellinteroperabilität sind zwischen Clients und prozessinternen Objekten zulässig. Die Interaktion zwischen einem Client und einem In-Process-Objekt, das unterschiedliche Threadingmodelle verwendet, ähnelt genau der Interaktion zwischen Clients und Out-of-Process-Servern. Wenn sich bei einem Prozessserver das Threadingmodell des Clients und des Prozessservers unterscheidet, muss COM sich zwischen dem Client und dem Objekt zwischensetzen.
Wenn ein Prozessobjekt, das das Einzelthreadmodell unterstützt, von mehreren Threads eines Clients gleichzeitig aufgerufen wird, kann COM den Clientthreads nicht erlauben, direkt auf die Schnittstelle des Objekts zuzugreifen. Stattdessen muss COM sicherstellen, dass Aufrufe synchronisiert werden und nur vom Clientthread ausgeführt werden, der das Objekt erstellt hat. Daher erstellt COM das Objekt im Standard Apartment des Clients und erfordert, dass alle anderen Client-Apartments mithilfe von Proxys auf das Objekt zugreifen.
Wenn ein Freethread-Apartment (Multithread-Apartmentmodell) in einem Client einen In-Prozess-Server mit Apartmentthread erstellt, löst COM einen Singlethread-Hostthread-Thread für das Apartmentmodell im Client aus. Dieser Hostthread erstellt das Objekt, und der Schnittstellenzeiger wird zurück an das Freethread-Apartment des Clients ge marshallt. Wenn ein Singlethread-Apartment in einem Apartmentmodellclient einen In-Prozess-Server mit Freithread erstellt, wird von COM ein Freethread-Hostthread (Multithread-Apartment, für das das Objekt erstellt und dann zurück an das Singlethread-Client-Apartment gemarst wird) gestartet.
Hinweis
Wenn Sie eine benutzerdefinierte Schnittstelle auf einem Prozessserver entwerfen, sollten Sie im Allgemeinen auch den Marshallingcode dafür bereitstellen, damit COM die Schnittstelle zwischen Client-Apartments marshallen kann.
COM hilft beim Schutz des Zugriffs auf Objekte, die von einer Singlethread-DLL bereitgestellt werden, indem der Zugriff aus demselben Client-Apartment erforderlich ist, in dem sie erstellt wurden. Darüber hinaus sollten alle DLL-Einstiegspunkte (z . B. DllGetClassObject und DllCanUnloadNow) und globale Daten immer von demselben Apartment aufgerufen werden. COM erstellt solche Objekte im Standard-Apartment des Clients und ermöglicht dem Standard-Apartment direkten Zugriff auf die Zeiger des Objekts. Aufrufe aus den anderen Wohnungen verwenden Interthread Marshaling, um vom Proxy zum Stub im Standard Apartment und dann zum Objekt zu gelangen. Dadurch kann COM Aufrufe mit dem -Objekt synchronisieren. Interthreadaufrufe sind langsam, daher wird empfohlen, diese Server so umzuschreiben, dass sie mehrere Apartments unterstützen.
Auf ein Objekt, das von einer Apartmentmodell-DLL bereitgestellt wird, muss wie bei einem Prozessserver mit einem Singlethread auf dasselbe Client-Apartment zugegriffen werden, von dem aus es erstellt wurde. Von diesem Server bereitgestellte Objekte können jedoch in mehreren Apartments des Clients erstellt werden, sodass der Server seine Einstiegspunkte (z . B. DllGetClassObject und DllCanUnloadNow) für die Multithreadverwendung implementieren muss. Wenn beispielsweise zwei Apartments eines Clients versuchen, zwei Instanzen des prozessinternen Objekts gleichzeitig zu erstellen, kann DllGetClassObject von beiden Apartments gleichzeitig aufgerufen werden. DllCanUnloadNow muss geschrieben werden, damit die DLL nicht entladen wird, während code noch in der DLL ausgeführt wird.
Wenn die DLL nur einen instance der Klassenfactory zum Erstellen aller Objekte bereitstellt, muss die Implementierung der Klassenfactory auch für die Verwendung mit Multithreads konzipiert werden, da mehrere Client-Apartments darauf zugreifen. Wenn die DLL bei jedem Aufruf von DllGetClassObject eine neue instance der Klassenfactory erstellt, muss die Klassenfactory nicht threadsicher sein.
Objekte, die von der Klassenfactory erstellt wurden, müssen nicht threadsicher sein. Nach der Erstellung durch einen Thread wird immer über diesen Thread auf das Objekt zugegriffen, und alle Aufrufe des Objekts werden von COM synchronisiert. Das Apartmentmodell eines Clients, der dieses Objekt erstellt, erhält einen direkten Zeiger auf das Objekt. Client-Apartments, die sich von dem Apartment unterscheiden, in dem das Objekt erstellt wurde, müssen über Proxys auf das Objekt zugreifen. Diese Proxys werden erstellt, wenn der Client die Schnittstelle zwischen seinen Apartments marshallt.
Wenn ein In-Process-DLL-ThreadingModel-Wert auf "Both" festgelegt ist, kann ein von dieser DLL bereitgestelltes Objekt direkt (ohne Proxy) in Singlethread- oder Multithread-Clientapartments erstellt und verwendet werden. Es kann jedoch nur direkt innerhalb der Wohnung verwendet werden, in der es erstellt wurde. Um das Objekt einem anderen Apartment zu übergeben, muss das Objekt gemarst werden. Das DLL-Objekt muss eine eigene Synchronisierung implementieren und kann von mehreren Clientappartements gleichzeitig zugegriffen werden.
Um die Leistung für den Freethread-Zugriff auf dll-Objekte in Prozessen zu beschleunigen, stellt COM die CoCreateFreeThreadedMarshaler-Funktion bereit. Diese Funktion erstellt ein Freithread-Marshallobjekt, das mit einem prozessinternen Serverobjekt aggregiert werden kann. Wenn ein Clientapartment im selben Prozess Zugriff auf ein Objekt in einem anderen Apartment benötigt, bietet das Aggregieren des Freethread-Marshallers dem Client einen direkten Zeiger auf das Serverobjekt und nicht auf einen Proxy, wenn der Client die Schnittstelle des Objekts zu einem anderen Apartment marshallt. Der Client muss keine Synchronisierung durchführen. Dies funktioniert nur innerhalb desselben Prozesses; Standard marshalling wird für einen Verweis auf das Objekt verwendet, das an einen anderen Prozess gesendet wird.
Ein Von einer Prozess-DLL bereitgestelltes Objekt, das nur freies Threading unterstützt, ist ein Freithreadobjekt. Es implementiert eine eigene Synchronisierung und kann von mehreren Clientthreads gleichzeitig aufgerufen werden. Dieser Server marshallt keine Schnittstellen zwischen Threads, sodass dieser Server direkt (ohne Proxy) nur von Multithread-Apartments in einem Client erstellt und verwendet werden kann. Singlethread-Apartments, die sie erstellen, greifen über einen Proxy darauf zu.
Zugehörige Themen