Prozesse, Threads und Wohnungen

Ein Prozess ist eine Sammlung von virtuellen Speicherplatz, Code, Daten und Systemressourcen. Ein Thread- ist Code, der in einem Prozess serial ausgeführt werden soll. Ein Prozessor führt Threads aus, nicht Prozesse, sodass jede Anwendung über mindestens einen Prozess verfügt, und ein Prozess verfügt immer über mindestens einen Thread der Ausführung, der als primärer Thread bezeichnet wird. Ein Prozess kann zusätzlich zum primären Thread mehrere Threads enthalten.

Prozesse kommunizieren miteinander über Nachrichten, wobei die Remoteprozeduraufruftechnologie (RPC) von Microsoft verwendet wird, um Informationen aneinander zu übergeben. Der Anrufer unterscheidet sich nicht zwischen einem Anruf von einem Prozess auf einem Remotecomputer und einem Anruf, der von einem anderen Prozess auf demselben Computer stammt.

Wenn ein Thread mit der Ausführung beginnt, wird er fortgesetzt, bis er beendet wird oder bis er von einem Thread mit höherer Priorität unterbrochen wird (durch eine Benutzeraktion oder den Threadplaner des Kernels). Jeder Thread kann separate Codeabschnitte ausführen, oder mehrere Threads können denselben Codeabschnitt ausführen. Threads, die denselben Codeblock ausführen, verwalten separate Stapel. Jeder Thread in einem Prozess teilt die globalen Variablen und Ressourcen dieses Prozesses.

Der Threadplaner bestimmt, wann und wie oft ein Thread ausgeführt werden soll, entsprechend einer Kombination des Prioritätsklassenattributes des Prozesses und der Basispriorität des Threads. Sie legen das Prioritätsklassenattribut eines Prozesses fest, indem Sie die funktion SetPriorityClass aufrufen und die Basispriorität eines Threads mit einem Aufruf von SetThreadPriority-festlegen.

Multithread-Anwendungen müssen zwei Threadingprobleme vermeiden: Deadlocks und Rennen. Ein Deadlock tritt auf, wenn jeder Thread auf die andere wartet, um etwas zu tun. Das COM-Aufrufsteuerelement verhindert Deadlocks in Aufrufen zwischen Objekten. Eine Racebedingung tritt auf, wenn ein Thread vor einem anderen abgeschlossen wird, von dem er abhängt, sodass der erste einen nicht initialisierten Wert verwendet, weil der zweite noch keinen gültigen Wert bereitgestellt hat. COM stellt einige Funktionen bereit, die speziell entwickelt wurden, um Rennbedingungen in Out-of-Process-Servern zu vermeiden. (Siehe Out-of-Process Server Implementation Helpers.)

Die Wohnung und die COM Threading-Architektur

Während COM das single-thread-pro-Process-Modell unterstützt, das vor der Einführung mehrerer Ausführungsthreads vorherrscht, können Sie Code schreiben, um mehrere Threads zu nutzen, was zu effizienteren Anwendungen führt, indem sie zulassen, dass ein Thread ausgeführt wird, während ein anderer Thread auf einen zeitaufwendigen Vorgang wartet.

Anmerkung

Die Verwendung mehrerer Threads ist keine Garantie für eine bessere Leistung. Da threadfaktoring ein schwieriges Problem darstellt, verursacht die Verwendung mehrerer Threads häufig Leistungsprobleme. Der Schlüssel besteht darin, mehrere Threads nur zu verwenden, wenn Sie sehr sicher sind, was Sie tun.

 

Im Allgemeinen versteht man die COM-Threadingarchitektur am einfachsten, wenn man sich alle COM-Objekte im Prozess als in Gruppen unterteilt vorstellt, die als Apartments bezeichnet werden. Ein COM-Objekt lebt in genau einer Wohnung, in dem Sinne, dass seine Methoden legal nur von einem Thread aufgerufen werden können, der zu dieser Wohnung gehört. Jeder andere Thread, der das Objekt aufrufen möchte, muss einen Proxy durchlaufen.

Es gibt zwei Arten von Wohnungen: Singlethread-Wohnungenund Multithread-Wohnungen.

Important

Auswählen eines Apartmentmodells (STA vs MTA):

Wohnung CoInitializeEx Markierung Verwenden Sie, wenn
STA (mit einem Thread) COINIT_APARTMENTTHREADED Ihr Thread verfügt über eine Nachrichtenschleife (UI-Threads), oder Sie verwenden COM-Objekte, die eine Nachrichtenpumpe erfordern (ActiveX-Steuerelemente, Shell-Objekte, Drag-and-Drop).
MTA (multithreadfähig) COINIT_MULTITHREADED Ihr Thread führt Hintergrundarbeit ohne Nachrichtenschleife durch, und die verwendeten COM-Objekte sind threadsicher oder agil.

Allgemeiner Deadlock-Fall: Ein STA-Thread muss Meldungen (über GetMessage/DispatchMessage oder gleichwertig) pumpen. Wenn ein STA-Thread auf einer Synchronisationsprimitive (z. B. WaitForSingleObject) blockiert, ohne Nachrichten zu verarbeiten, werden eingehende COM-Aufrufe an Objekte in diesem Apartment niemals zugestellt – was zu Deadlocks führt. Verwenden Sie CoWaitForMultipleHandles oder MsgWaitForMultipleObjects anstelle von direkten Wartevorgängen in einem STA-Thread.

  • Singlethread-Wohnungen bestehen aus genau einem Thread, sodass alle COM-Objekte, die in einer Singlethread-Wohnung leben, Methodenaufrufe nur von dem Thread empfangen können, der zu dieser Wohnung gehört. Alle Methodenaufrufe für ein COM-Objekt in einem Single-Thread-Apartment werden mit der Windows-Nachrichtenwarteschlange für den Thread des Single-Thread-Apartments synchronisiert. Ein Prozess mit einem einzelnen Ausführungsthread ist einfach ein Sonderfall dieses Modells.
  • Multithread-Wohnungen bestehen aus einem oder mehreren Threads, sodass alle COM-Objekte, die in einer Multithread-Wohnung leben, Methodenaufrufe direkt von jedem der Threads empfangen können, die zur Multithread-Wohnung gehören. Threads in einem Multithread-Apartment verwenden ein Modell namens Free-Threading. Aufrufe an COM-Objekte in einem Multithread-Apartment werden von den Objekten selbst synchronisiert.

Anmerkung

Eine Beschreibung der Kommunikation zwischen Singlethread-Apartments und Multithread-Apartments innerhalb des gleichen Prozesses finden Sie unter Single-Threaded‑ und Multithreaded-Kommunikation.

 

Ein Prozess kann null oder mehr Singlethread-Apartments und null oder ein Multithread-Apartment haben.

In einem Prozess wird das Hauptapartment als erstes initialisiert. In einem Single-Threaded-Prozess ist dies das einzige Apartment. Anrufparameter werden zwischen Apartments gemarshallt, und COM übernimmt die Synchronisierung über den Nachrichtenaustausch. Wenn Sie mehrere Threads in einem Prozess als freie Threads festlegen, befinden sich alle freien Threads in einem einzigen Apartment, die Parameter werden direkt an jeden Thread im Apartment übergeben, und Sie müssen die gesamte Synchronisierung selbst übernehmen. In einem Prozess mit freiem Threading und Apartment-Threading befinden sich alle freien Threads in einem einzigen Apartment, und alle anderen Apartments sind Single-Thread-Apartments. Ein Prozess, der mit COM arbeitet, besteht aus einer Sammlung von Apartments mit höchstens einem Multithread-Apartment, aber beliebig vielen Single-Threaded-Apartments.

Die Threadingmodelle in COM stellen den Mechanismus für Clients und Server bereit, die verschiedene Threadingarchitekturen verwenden, um zusammenzuarbeiten. Aufrufe zwischen Objekten mit unterschiedlichen Threadingmodellen in verschiedenen Prozessen werden natürlich unterstützt. Aus Sicht des aufrufenden Objekts laufen alle Aufrufe von Objekten außerhalb eines Prozesses gleich ab, unabhängig davon, welchem Threadingmodell das aufgerufene Objekt zugeordnet ist. Ebenso verhalten sich eingehende Aufrufe aus der Perspektive des aufgerufenen Objekts unabhängig vom Threadingmodell des Aufrufers identisch.

Die Interaktion zwischen einem Client und einem Out-of-Process-Objekt ist auch dann einfach, wenn sie unterschiedliche Threadingmodelle verwenden, da sich der Client und das Objekt in verschiedenen Prozessen befinden. COM kann, zwischen Client und Server zwischengeschaltet, den Code bereitstellen, damit die Threadingmodelle unter Verwendung von Standard-Marshaling und RPC zusammenarbeiten können. Wenn z. B. ein Singlethread-Objekt von mehreren Freethread-Clients gleichzeitig aufgerufen wird, werden die Aufrufe von COM synchronisiert, indem entsprechende Fenstermeldungen in der Nachrichtenwarteschlange des Servers platziert werden. Das Apartment des Objekts erhält jedes Mal einen Anruf, wenn es Nachrichten abruft und sendet. Es muss jedoch darauf geachtet werden, dass prozessinterne Server ordnungsgemäß mit ihren Clients interagieren. (Siehe Probleme bei der Threadverarbeitung von In-Process-Servern.)

Das wichtigste Problem bei der Programmierung mit einem Multithreadmodell besteht darin, ihren Codethread sicher zu machen, damit Nachrichten, die für einen bestimmten Thread vorgesehen sind, nur zu diesem Thread wechseln und der Zugriff auf Threads geschützt ist.

Weitere Informationen finden Sie in den folgenden Themen: