Synchrone und überlappende Pipe-E/A

Die Funktionen ReadFile, WriteFile, TransactNamedPipe und ConnectNamedPipe können Eingabe- und Ausgabevorgänge für eine Pipe entweder synchron oder asynchron ausführen. Wenn eine Funktion synchron ausgeführt wird, wird sie erst zurückgegeben, wenn der ausgeführte Vorgang abgeschlossen ist. Dies bedeutet, dass die Ausführung des aufrufenden Threads auf unbestimmte Zeit blockiert werden kann, während auf den Abschluss eines zeitaufwändigen Vorgangs gewartet wird. Wenn eine Funktion asynchron ausgeführt wird, wird sie sofort zurückgegeben, auch wenn der Vorgang noch nicht abgeschlossen wurde. Dadurch kann ein zeitaufwändiger Vorgang im Hintergrund ausgeführt werden, während der aufrufende Thread andere Aufgaben ausführen kann.

Die Verwendung asynchroner E/A ermöglicht es einem Pipeserver, eine Schleife zu verwenden, die die folgenden Schritte ausführt:

  1. Geben Sie in einem Aufruf der Wait-Funktion mehrere Ereignisobjekte an, und warten Sie, bis eines der Objekte auf den signalierten Zustand festgelegt wird.
  2. Verwenden Sie den Rückgabewert der Wait-Funktion, um zu bestimmen, welcher überlappende Vorgang abgeschlossen wurde.
  3. Führen Sie die erforderlichen Aufgaben aus, um den abgeschlossenen Vorgang zu sauber und den nächsten Vorgang für dieses Pipehandle zu initiieren. Dies kann das Starten eines weiteren überlappenden Vorgangs für dasselbe Pipehandle umfassen.

Überlappende Vorgänge ermöglichen es, dass eine Pipe Daten gleichzeitig lesen und schreiben kann und ein einzelner Thread gleichzeitig E/A-Vorgänge für mehrere Pipehandles ausführt. Dadurch kann ein Singlethread-Pipeserver die Kommunikation mit mehreren Pipeclients effizient verarbeiten. Ein Beispiel finden Sie unter Named Pipe-Server mit überlappenden E/A-Vorgängen.

Damit ein Pipeserver synchrone Vorgänge für die Kommunikation mit mehr als einem Client verwenden kann, muss er einen separaten Thread für jeden Pipeclient erstellen, damit mindestens ein Thread ausgeführt werden kann, während andere Threads warten. Ein Beispiel für einen Multithreadpipeserver, der synchrone Vorgänge verwendet, finden Sie unter Multithreaded Pipe Server.

Aktivieren des asynchronen Vorgangs

Die Funktionen ReadFile, WriteFile, TransactNamedPipe und ConnectNamedPipe können nur asynchron ausgeführt werden, wenn Sie den Überlappungsmodus für das angegebene Pipehandle aktivieren und einen gültigen Zeiger auf eine OVERLAPPED-Struktur angeben. Wenn der OVERLAPPED-ZeigerNULL ist, kann der Rückgabewert der Funktion fälschlicherweise angeben, dass der Vorgang abgeschlossen wurde. Daher wird dringend empfohlen, wenn Sie ein Handle mit FILE_FLAG_OVERLAPPED erstellen und asynchrones Verhalten verwenden möchten, immer eine gültige OVERLAPPED-Struktur anzugeben.

Der hEvent-Member der angegebenen OVERLAPPED-Struktur muss ein Handle für ein Ereignisobjekt mit manueller Zurücksetzung enthalten. Dies ist ein Synchronisierungsobjekt, das von der CreateEvent-Funktion erstellt wird. Der Thread, der den überlappenden Vorgang initiiert, verwendet das Ereignisobjekt, um zu bestimmen, wann der Vorgang abgeschlossen ist. Sie sollten das Pipehandle nicht für die Synchronisierung verwenden, wenn Sie gleichzeitige Vorgänge für dasselbe Handle ausführen, da es keine Möglichkeit gibt, zu wissen, welcher Vorgang abgeschlossen hat, dass das Pipehandle signalisiert wurde. Die einzige zuverlässige Technik zum Ausführen gleichzeitiger Vorgänge für dasselbe Pipehandle ist die Verwendung einer separaten OVERLAPPED-Struktur mit einem eigenen Ereignisobjekt für jeden Vorgang. Weitere Informationen zu Ereignisobjekten finden Sie unter Synchronisierung.

Außerdem können Sie benachrichtigt werden, wenn ein überlappender Vorgang abgeschlossen wird, indem Sie die Funktionen GetQueuedCompletionStatus oderGetQueuedCompletionStatusEx verwenden. In diesem Fall müssen Sie das Ereignis für manuelles Zurücksetzen nicht in der OVERLAPPED-Struktur zuweisen, und die Vervollständigung erfolgt für das Pipehandle auf die gleiche Weise wie bei einem asynchronen Lese- oder Schreibvorgang. Weitere Informationen finden Sie unter E/A-Vervollständigungsports.

Wenn Die Vorgänge ReadFile, WriteFile, TransactNamedPipe und ConnectNamedPipe asynchron ausgeführt werden, tritt einer der folgenden Vorgänge auf:

  • Wenn der Vorgang abgeschlossen ist, wenn die Funktion zurückgegeben wird, gibt der Rückgabewert den Erfolg oder Fehler des Vorgangs an. Wenn ein Fehler auftritt, ist der Rückgabewert null, und die GetLastError-Funktion gibt etwas anderes als ERROR_IO_PENDING zurück.
  • Wenn der Vorgang nicht abgeschlossen wurde, wenn die Funktion zurückgegeben wird, ist der Rückgabewert null, und GetLastError gibt ERROR_IO_PENDING zurück. In diesem Fall muss der aufrufende Thread warten, bis der Vorgang abgeschlossen ist. Der aufrufende Thread muss dann die GetOverlappedResult-Funktion aufrufen, um die Ergebnisse zu bestimmen.

Verwenden von Vervollständigungsroutinen

Die Funktionen ReadFileEx und WriteFileEx stellen eine weitere Form von überlappenden E/A-Vorgängen bereit. Im Gegensatz zu den überlappenden Funktionen ReadFile und WriteFile , die ein Ereignisobjekt zum Signalisieren der Vervollständigung verwenden, geben die erweiterten Funktionen eine Vervollständigungsroutine an. Eine Vervollständigungsroutine ist eine Funktion, die zur Ausführung in die Warteschlange eingereiht wird, wenn der Lese- oder Schreibvorgang abgeschlossen ist. Die Vervollständigungsroutine wird erst ausgeführt, wenn der Thread, der ReadFileEx und WriteFileEx aufgerufen hat, einen warnbaren Wartevorgang startet, indem eine der warnbaren Wartefunktionen aufgerufen wird, wobei der fAlertable-Parameter auf TRUE festgelegt ist. In einem warnbaren Wartevorgang werden die Funktionen auch zurückgegeben, wenn eine ReadFileEx- oder WriteFileEx-Vervollständigungsroutine für die Ausführung in die Warteschlange eingereiht wird. Ein Pipeserver kann die erweiterten Funktionen verwenden, um eine Sequenz von Lese- und Schreibvorgängen für jeden Client auszuführen, der eine Verbindung mit diesem Client herstellt. Jeder Lese- oder Schreibvorgang in der Sequenz gibt eine Vervollständigungsroutine an, und jede Abschlussroutine initiiert den nächsten Schritt in der Sequenz. Ein Beispiel finden Sie unter Named Pipe Server Using Completion Routines.