COM & Threading „The Basics“ Frank Lange Michael Willers Microsoft GmbH

Preview:

DESCRIPTION

COM & Threading „The Basics“ Frank Lange Michael Willers Microsoft GmbH. Agenda. Warum COM-Threading ? Wie funktioniert’s? Wo gibt’s weitere Info’s?. Warum COM-Threading? Ein einfaches Beispiel. Zwei Threads innerhalb eines Prozesses erzeugen das gleiche COM-Object. - PowerPoint PPT Presentation

Citation preview

COM & Threading„The Basics“

Frank LangeMichael Willers

Microsoft GmbH

Warum COM-Threading? Wie funktioniert’s? Wo gibt’s weitere Info’s?

Agenda

ObjectObject(Instanz 1)(Instanz 1)

Thread 2Thread 2

ObjectObject(Instanz 2)(Instanz 2)

Thread 1Thread 1

Zwei Zwei Threads Threads innerhalb innerhalb eines Prozesses eines Prozesses erzeugen erzeugen das gleiche COM-Object.das gleiche COM-Object.

Ist der COM-Server eine Ist der COM-Server eine DLL (in-proc) dann DLL (in-proc) dann greifen greifen diedie Methoden Methoden beidebeider r ObjektObjektinstanzeninstanzen auf die auf die gleichen gleichen globalen Datenglobalen Daten zuzu..

Sofern dSofern derer ZugriffZugriff nicht nicht threadsafe threadsafe istist “krachts”, “krachts”, wenn beide Threads auf wenn beide Threads auf die globalen Daten die globalen Daten zugreifen.zugreifen.

Glo

bale

Dat

enG

loba

le D

aten

Warum COM-Threading?Ein einfaches Beispiel

?? ??????

Warum COM-Threading?Was bedeutet Threading Model?!

Im “Multithread-Betrieb” können in “bestimmten” Situationen keine direkten Methodenaufrufe erfolgen.

In diesen Situationen ist Marshalling notwendig; Aufrufe werden langsamer!

Wann ist das Marshalling notwendig?

Warum COM-Threading?“Brauchen“ Sie performante Objekte?

Standardmäßig “schützt” COM die Objekte vor dem Zugriff konkurrierender Threads (SingleThreading).• Zugriffe werden synchronisiert (Standard!)• Client braucht nicht darauf zu achten, ob das

Objekt threadsafe ist Bei “echtem” Multithreading muß der

Entwickler dafür sorgen, daß die Objekte threadsafe sind !!!

Threading wird mit Apartments realisiert.

Wie funktioniert‘s?Allgemeines, I

Ein Apartment ist eine Gruppe von Objekten innerhalb eines Prozesses.

Apartments werden benutzt, um eine Zuordnung zwischen Threads und Objekten herzustellen.

Ein Prozeß kann ein oder mehrere Apartments beinhalten.

Wie funktioniert‘s?Was bedeutet Apartment?

Apartment CApartment CApartment BApartment BApartment AApartment A

ProProzess zess YYProProzesszess X X

Wie funktioniert‘s?Beispiele für Apartments

Single-threaded apartments (STAs)• pro Apartment nur ein einziger Thread• beliebig viele STAs pro Prozess• Der innerhalb eines Prozesses zuerst

erzeugte STA heißt main STA Multithreaded apartments (MTAs)

• beliebig viele Threads pro MTA• ein Prozess kann nur genau ein MTA

beinhalten

Wie funktioniert‘s?Was bedeutet Apartment?

Jeder Thread, der mit COM-Objekten arbeitet, muß vorher CoInitialize oder CoInitializeEx aufrufen.• Mit diesem Aufruf “betritt” der Thread ein

Apartment• Jedes Objekt befindet sich in einem

Apartment Objekte in unterschiedlichen Apartments

können nicht “direkt” aufgerufen werden.In diesem Fall ist Marshalling notwendig!• gilt auch innerhalb eines Prozesses!

Wie funktioniert‘s?Allgemeines, II

Thread 1Thread 1

Thread 2Thread 2

mmain STAain STA

STASTA

Thread 3Thread 3

MTAMTA

Thread 4Thread 4

ProzeProze ssss

Marshalling

Wie funktioniert‘s?Objekte, Threads und Apartments

Marshalling

“Ziel-Apartment” ist ein STA…• Aufrufe werden an den “one and only”

Thread des STA weitergeleitet und nacheinander abgearbeitet (serially)

• Aufruf wird mit einer Nachricht realisiert, die an ein von COM erzeugtes “hidden window” gesendet wird (message queuing!)

“Ziel-Apartment” ist ein MTA…• Aufrufe geschehen quasi “gleichzeitig”

(concurrency) via (L)RPC

Wie funktioniert‘s?Aufrufe in andere Apartments

Der 2. Parameter von CoInitializeEx (COINIT-Wert) legt fest, in welchem Apartment-Typ der Thread “läuft”. • COINIT_APARTMENTTHREADED

“setzt” den Thread in ein STA• COINIT_MULTITHREADED “setzt” den

Thread in ein MTA CoInitialize = CoInitializeEx (…,

COINIT_APARTMENTTHREADED )

Wie funktioniert‘s?Zuordnung: Threads und Apartments

Out-of-proc (EXE)• Der Server, in dem sich das Objekt befindet,

bestimmt den Apartmenttyp!• Die main-Funktion des Servers ruft

CoInitialize bzw. CoInitializeEx auf.• Reminder: Jeder Thread, der mit COM-Objekten

arbeitet, muß diese Funktion aufrufen

• D.h.: Der Apartmenttyp wird für alle Objekte des Servers festgelegt!• ACHTUNG: Wenn der Apartmenttyp MTA ist,

müssen alle Objekte des Servers threadsafe sein!

Wie funktioniert‘s?Zuordnung: Objekte und Apartments, I

In-proc (DLL)• Das Threading Model des Objekts

bestimmt den Apartmenttyp!• Das Threading Model ist in der Registry

gespeichert.• D.h.: Der Apartmenttyp wird für jedes

Objekt einzeln festgelegt!

Wie funktioniert‘s?Zuordnung: Objekte und Apartments, II

HKEY_CLASSES_ROOTHKEY_CLASSES_ROOT

CLSIDCLSID

{…}{…}

InprocServer32InprocServer32 ““C:\Servers\MyComp.dll”C:\Servers\MyComp.dll”

““My Component”My Component”

““Apartment”Apartment”““ThreadingModel”ThreadingModel”

An dieser Stelle ist das An dieser Stelle ist das Threading Model eingetragen!Threading Model eingetragen!

Wie funktioniert‘s?Threading Model in der Registry

No ThreadingModel value (=Single)• Alle Objekte “laufen” im main STA eines

Prozesses

Wie funktioniert‘s?Welche Threading Model‘s gibt es?, I

ThreadingModel=Apartment• Objekte können in jedem STA eines

Prozesses “laufen” ThreadingModel=Free

• Objekte “laufen” grundsätzlich nur im“one and only” MTA eines Prozesses

ThreadingModel=Both• Objekte können sowohl in einem STA als

auch im MTA eines Prozesses “laufen”

Wie funktioniert‘s?Welche Threading Model‘s gibt es?, II

COM “nimmt” an, daß Objekte nicht threadsafe sind.

COM “beschränkt” alle Objekt-Instanzen auf das main STA.• Aufrufe von ausserhalb werden

synchronisiert und erfolgen indirekt (marshalling)

Da alle Instanzen im gleichen Thread laufen kann immer nur eine einzige Instanz “Code ausführen”.• Voila! Thread safety!

Wie funktioniert‘s?No Threading Model (=Single)

Thread 1Thread 1 Instanz 1Instanz 1 Instanz 2Instanz 2

Thread 2Thread 2

mmain STAain STA

Alle anderen ApartmentsAlle anderen Apartments

ProxyProxy

Methodenaufrufe werden synchronisiert, Methodenaufrufe werden synchronisiert, da da ALLE Objekt-ALLE Objekt-Instanzen im gleichen Instanzen im gleichen ThreadThread „ „laufen”.laufen”. Somit sind gleichzeitige Somit sind gleichzeitige Zugriffe auf gloZugriffe auf globale Datenbale Daten nicht möglich. nicht möglich.

Marshalling

(gilt für Zugriffe „innerhalb“ von Methoden)(gilt für Zugriffe „innerhalb“ von Methoden)

Wie funktioniert‘s?No Threading Model (=Single)

COM “nimmt” an, daß Objekte “halbwegs” threadsafe sind und “setzt” Objekt in ein STA.

COM synchronisiert Methodenaufrufe innerhalb einzelner Objektinstanzen. Somit sind auch Member einer Instanz geschützt.

Methodenaufrufe unterschiedlicher Instanzen können gleichzeitig erfolgen. Wird innerhalb dieser Methoden auf globale Daten zugegriffen, muß dieser Zugriff threadsafe sein.

Jeder Thread, der in einem STA “läuft” kann dort Objekte erstellen. Zugriffe auf diese Objekte können aus MTA’s nur indirekt erfolgen (Marshalling).

Wie funktioniert‘s?Threading Model=Apartment

Thread 1Thread 1 Instanz 1Instanz 1

Instanz 2Instanz 2Thread 2Thread 2

mmain STAain STA

STASTA

Glo

bal D

aten

Glo

bal D

aten

Globale Daten werden Globale Daten werden nichtnicht vor “überlappenden” vor “überlappenden” Lese- und Schreibzugriffen Lese- und Schreibzugriffen verschiedener verschiedener Instanzen Instanzen geschütztgeschützt und müssen s und müssen synchronisiertynchronisiert werden.werden.

Wie funktioniert‘s?Threading Model=Apartment

COM “nimmt” an, das Objekte threadsafe sind. D.h.: “Concurrent calls” sind OK.• COM braucht Methodenaufrufe nicht zu

synchronisieren COM “setzt” Objekte in den MTA und alle

dortigen Threads können direkt, d.h. ohne Marshalling, auf die Objekte zugreifen.

Threads, die in STAs “laufen” können auf die Objekte im MTA nur indirekt zugreifen (Marshalling!).

Wie funktioniert‘s?Threading Model=Free

COM “nimmt” an, das Objekte grundsätzlich threadsafe sind. Ein Objekt kann in einem STA oder dem MTA angelegt werden.

Dadurch ist sichergestellt, daß das Objekt stets im Apartment des Client-Threads angelegt wird.• Es ist egal, ob der Client ein STA-Thread oder

ein MTA-Thread ist• Der Thread, der das Objekt angelegt hat, kann

stets direkt auf das Objekt zugreifen

Wie funktioniert‘s?Threading Model=Both

““Both”Both”

Kein Eintrag (none)Kein Eintrag (none)““Free”Free”

ThreadingModelThreadingModel

““Apartment”Apartment”DireDirekktt

ProxyProxyDireDirekktt

DireDirekktt

ProxyProxyProxyProxy

DireDirekktt

DireDirekkttProxyProxy

ProxyProxy DireDirekktt DireDirekktt

MTA ThreadMTA Thread

Alle Threads, die CoInitAlle Threads, die CoInitializeializeExExCOINIT_COINIT_MULTITHREADED)MULTITHREADED)aufrufenaufrufen

STA ThreadSTA Thread

Alle weiteren Threads, dieAlle weiteren Threads, die CoInitCoInitializeializeExEx((COINIT_COINIT_APAPARTMENTARTMENTTHREADED)THREADED) aufrufenaufrufen

Main STA ThreadMain STA Thread

AllerersterAllererster Thread, der CoInit Thread, der CoInitializeializeExEx(COINIT_(COINIT_APAPARARTTMENTMENTTHREADED)THREADED)aufruftaufruft

Wie funktioniert‘s?Wann erfolgt Marshalling?

Threading ModelThreading Model AktionAktion

None (Single)None (Single) nichtsnichts

ApartmentApartment Synchronisation für Synchronisation für Methodenzugriffe auf Methodenzugriffe auf globale Datenglobale Daten

FreeFree Synchronisation für Synchronisation für Methodenzugriffe auf Methodenzugriffe auf globale Daten und Instanzdaten (Member)globale Daten und Instanzdaten (Member)

BothBoth Synchronisation für Synchronisation für Methodenzugriffe auf Methodenzugriffe auf globale Daten und Instanzdaten (Member)globale Daten und Instanzdaten (Member)

Wie funktioniert‘s?Was muss implementiert werden?

Es gibt Objekte, die selbst Worker-Threads erzeugen: Diese Threads sollen vorhandene Schnittstellenzeiger benutzen.

Wenn man diese Objekte als "Both" deklariert und in einem STA erzeugt, müssen die Worker-Threads in anderen Apartments erzeugt werden.

Schnittstellenzeiger werden also„gemarshalled“. Dies kann bei häufigen Aufrufen erhebliche Performanceverluste verursachen.

Für diese Fälle kann man mit „Free" die Erzeugung im MTA erzwingen. Die Worker-Threads und das Objekt befinden sich dann im selben Apartment.

Wie funktioniert‘s?Warum „Free“ und „Both“

“No ThreadingModel”-Objekte sind einfach zu implementieren, allerdings ist fast immer Marshalling notwendig.

“ThreadingModel=Apartment”-Objekte verbessern die Performance mit relativ wenig Aufwand.

“ThreadingModel=Free/Both”-Objekte haben die beste Performance, sind aber schwierig zu implementieren und zu debuggen.

Wie funktioniert‘s?Zusammenfassung - Theading Model

Wenn das Threading Model auf Apartment “gesetzt” ist, dann muß der Zugriff auf globale Daten innerhalb von Objekt-Methoden grundsätzlich threadsafe erfolgen.• critical sections• Interlocked-functions

Sollen die Objekte im MTA “laufen” müssen alle Operationen innerhalb des Objekts threadsafe sein.

Wie funktioniert‘s?Zusammenfassung - Objekt

Jeder Thread muß vor dem Benutzen von COM-Objekten CoInitialize(Ex) aufrufen.• Thread “betritt” damit ein Apartment• kein Marshalling bei gleichem Apartmenttyp!

Schnittstellenzeiger dürfen niemals direkt an Threads in anderen Apartments übergeben werden.• Marshalling zwischen unterschiedlichen

Apartments!

Wie funktioniert‘s?Zusammenfassung - Client

Schnittstellenzeiger können zwischen Threads können nur dann direkt übergeben werden, wenn die Threads im gleichen Apartment “liegen”.

Liegen die Threads in unterschiedlichen Appartments ist Marshalling erforderlich.• CoMarshalInterThreadInterfaceInStream

marshals an interface in one thread• CoGetInterfaceAndReleaseStream

unmarshals the interface in another

Wie funktioniert‘s?Marshalling von Schnittstellenzeigern, I

// The following global variable will hold the IStream pointer used by// both threads. COM makes sure the IStream pointer can be safely// used in different apartments.IStream* g_pStream;IMath* pMath;

// Marshal the interface pointer in one thread.CoMarshalInterThreadInterfaceInStream (IID_IFace, pMath, g_pStream); . . .// Unmarshal it in another.IMath* pMath;CoGetInterfaceAndReleaseStream (g_pStream, IID_IFace, (void**) &pMath);

Ein Stream nimmt immer nur einen Schnittstellenzeiger auf!

Wie funktioniert‘s?Marshalling von Schnittstellenzeigern, II

Der FTM ist ein COM-Objekt, das ein “custom marshalling” zur Verfügung stellt.

Auf alle Objekte, die den FTM benutzen, kann grundsätzlich direkt zugegriffen werden• “mehr Speed”, aber:• hebelt Synchronisations-Mechanismen von

COM komplett aus!

Wie funktioniert‘s?Free-Threaded Marshaller (FTM)

Objekte müssen threadsafe sein, um den FTM zu benutzen.• Sofern “externe” Threads direkten Objekt-

zugriff haben, kann COM die Zugriffe nicht synchronisieren!

Der FTM sollte nicht von Objekten benutzt werden, die Objekte in anderen Apartments aufrufen.• Callbacks können Deadlocks erzeugen• Aufrufergebnis kann

RPC_E_WRONG_THREAD sein

Wie funktioniert‘s?Free-Threaded Marshaller (FTM)

Allgemeine Hinweise Multi-Threading: RPC-Call, total

blockierend Single-Threading: Messageloop Deshalb: Kein UI mit MTA!!! In-proc-Server (DLLs) werden beim

Beenden des Prozesses „entsorgt“!! Alternative: CoFreeUnusedLibraries oder

CoFreeAllLibraries aufrufen OLE32.DLL: COM-Runtime OLEAUT32.DLL: Automation, Standard-

Marshalling

Wo gibt’s weitere Info’s? msdn online

• http://www.microsoft.com/germany/msdn Microsoft Systems Journal

• diverse Artikel, z.B. Heft 4/1997 (!) Bücher von WROX Press

• http://www.wrox.com Bücher von Microsoft Press

• Inside COM, Dale Rogerson Knowledge-Base-Artikel Q150777!!!

Fragen!?

Uff...Uff...