Asynchrone Prozeduraufrufe

Ein asynchroner Prozeduraufruf (Asynchroner Prozeduraufruf ) ist eine Funktion, die asynchron im Kontext eines bestimmten Threads ausgeführt wird. Wenn ein APC in eine Warteschlange für einen Thread eingereiht wird, gibt das System einen Software-Interrupt aus. Wenn der Thread das nächste Mal geplant ist, wird die APC-Funktion ausgeführt. Ein vom System generierter APC wird als Kernelmodus-APC bezeichnet. Ein von einer Anwendung generierter APC wird als Benutzermodus-APC bezeichnet. Ein Thread muss sich in einem warnbaren Zustand befinden, um einen Benutzermodus-APC auszuführen.

Jeder Thread verfügt über eine eigene APC-Warteschlange. Eine Anwendung stellt einen APC mit einem Thread in die Warteschlange, indem die QueueUserAPC-Funktion aufgerufen wird . Der aufrufende Thread gibt die Adresse einer APC-Funktion im Aufruf von QueueUserAPC an. Das Warteschlangening eines APC ist eine Anforderung für den Thread, die APC-Funktion aufzurufen.

Wenn ein Benutzermodus-APC in die Warteschlange eingereiht wird, wird der Thread, für den er in die Warteschlange gestellt wird, nicht zum Aufrufen der APC-Funktion angewiesen, es sei denn, sie befindet sich in einem warnbaren Zustand. Ein Thread wechselt in einen warnbaren Zustand, wenn er die Funktionen SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx oder WaitForSingleObjectEx aufruft . Wenn die Wartezeit vor der APC-Warteschlange erfüllt ist, befindet sich der Thread nicht mehr in einem warnbaren Wartezustand, sodass die APC-Funktion nicht ausgeführt wird. Der APC befindet sich jedoch weiterhin in der Warteschlange, sodass die APC-Funktion ausgeführt wird, wenn der Thread eine weitere warnbare Wartefunktion aufruft.

Die Funktionen ReadFileEx, SetWaitableTimer, SetWaitableTimerEx und WriteFileEx werden mithilfe eines APC als Vervollständigungsbenachrichtigungsrückrufmechanismus implementiert.

Wenn Sie einen Threadpool verwenden, beachten Sie, dass APCs nicht so gut funktionieren wie andere Signalmechanismen, da das System die Lebensdauer von Threadpoolthreads steuert, sodass es möglich ist, dass ein Thread beendet wird, bevor die Benachrichtigung übermittelt wird. Anstatt einen APC-basierten Signalisierungsmechanismus wie den pfnCompletionRoutine-Parameter von SetWaitableTimer oder SetWaitableTimerEx zu verwenden, verwenden Sie ein wartebares Objekt, z. B. einen mit CreateThreadpoolTimer erstellten Timer. Verwenden Sie für E/A ein mit CreateThreadpoolIo erstelltes E/A-Vervollständigungsobjekt oder eine hEvent-basierteOVERLAPPED-Struktur , in der das Ereignis an die SetThreadpoolWait-Funktion übergeben werden kann.

Interne Synchronisierung

Wenn eine E/A-Anforderung ausgestellt wird, wird eine Struktur zugewiesen, um die Anforderung darzustellen. Diese Struktur wird als E/A-Anforderungspaket (IRP) bezeichnet. Bei synchronen E/A erstellt der Thread die IRP, sendet sie an den Gerätestapel und wartet im Kernel, bis die IRP abgeschlossen ist. Bei asynchroner E/A erstellt der Thread die IRP und sendet sie an den Gerätestapel. Der Stapel kann die IRP sofort abschließen oder eine ausstehende status zurückgeben, die angibt, dass die Anforderung in Bearbeitung ist. In diesem Fall wird der IRP weiterhin dem Thread zugeordnet, sodass er abgebrochen wird, wenn der Thread beendet oder eine Funktion wie CancelIo aufruft. In der Zwischenzeit kann der Thread weiterhin andere Aufgaben ausführen, während der Gerätestapel die IRP weiter verarbeitet.

Es gibt mehrere Möglichkeiten, wie das System angeben kann, dass die IRP abgeschlossen wurde:

  • Aktualisieren Sie die überlappende Struktur mit dem Ergebnis des Vorgangs, damit der Thread abfragen kann, um festzustellen, ob der Vorgang abgeschlossen wurde.
  • Signalisieren Sie das Ereignis in der überlappenden Struktur, damit ein Thread für das Ereignis synchronisiert und nach Abschluss des Vorgangs geweckt werden kann.
  • Stellen Sie die IRP mit dem ausstehenden APC des Threads in eine Warteschlange, damit der Thread die APC-Routine ausführt, wenn sie in einen warnbaren Wartezustand wechselt, und kehren Sie vom Wartevorgang mit einem status zurück, der angibt, dass eine oder mehrere APC-Routinen ausgeführt wurden.
  • Warteschlange des IRP an einem E/A-Abschlussport, wo er vom nächsten Thread ausgeführt wird, der auf den Abschlussport wartet.

Threads, die an einem E/A-Vervollständigungsport warten, warten nicht in einem warnbaren Zustand. Wenn diese Threads DAHER IRPs ausgeben, die als APCs für den Thread abgeschlossen sind, werden diese IPC-Vervollständigungen nicht rechtzeitig durchgeführt. Sie treten nur auf, wenn der Thread eine Anforderung vom E/A-Vervollständigungsport empfängt und dann in eine warnbare Wartezeit eintritt.

Verwenden eines wartebaren Timers mit einem asynchronen Prozeduraufruf