Freigeben über


Synchrone und überlappende Rohr-E/A

Die ReadFile-, WriteFile-, TransactNamedPipe-und ConnectNamedPipe- Funktionen 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 auszuführende Vorgang abgeschlossen ist. Dies bedeutet, dass die Ausführung des aufrufenden Threads für einen unbestimmten Zeitraum blockiert werden kann, während er auf einen zeitaufwendigen Vorgang wartet. Wenn eine Funktion asynchron ausgeführt wird, wird sie sofort zurückgegeben, auch wenn der Vorgang nicht abgeschlossen wurde. Dadurch kann ein zeitaufwändiger Vorgang im Hintergrund ausgeführt werden, während der aufrufende Thread frei ist, andere Aufgaben auszuführen.

Durch die Verwendung asynchroner E/A-Vorgänge kann ein Pipeserver eine Schleife verwenden, die die folgenden Schritte ausführt:

  1. Geben Sie mehrere Ereignisobjekte in einem Aufruf der Wartefunktion an, und warten Sie, bis eines der Objekte auf den signalierten Zustand festgelegt wird.
  2. Verwenden Sie den Rückgabewert der Wartefunktion, um zu bestimmen, welcher überlappende Vorgang abgeschlossen ist.
  3. Führen Sie die erforderlichen Aufgaben aus, um den abgeschlossenen Vorgang zu bereinigen und den nächsten Vorgang für diesen Rohrziehpunkt zu initiieren. Dies kann das Starten eines anderen überlappenden Vorgangs für denselben Rohrziehpunkt umfassen.

Überlappende Vorgänge ermöglichen es einem Rohr, Daten gleichzeitig zu lesen und zu schreiben und für einen einzelnen Thread gleichzeitige E/A-Vorgänge auf mehreren Rohrziehpunkten auszuführen. Auf diese Weise kann ein Singlethread-Pipeserver die Kommunikation mit mehreren Pipeclients effizient verarbeiten. Ein Beispiel finden Sie unter Named Pipe Server Using Overlapped I/O.

Damit ein Pipeserver synchrone Vorgänge für die Kommunikation mit mehreren Clients verwendet, muss er für jeden Pipeclient einen separaten Thread erstellen, damit ein oder mehrere Threads ausgeführt werden können, während andere Threads warten. Ein Beispiel für einen Multithread-Pipeserver, der synchrone Vorgänge verwendet, finden Sie unter Multithreaded Pipe Server.

Aktivieren eines asynchronen Vorgangs

Die funktionen ReadFile, WriteFile, TransactNamedPipeund ConnectNamedPipe funktionen können nur asynchron ausgeführt werden, wenn Sie den überlappenden Modus für den angegebenen Rohrziehpunkt aktivieren und einen gültigen Zeiger auf eine OVERLAPPED Struktur angeben. Wenn der ÜBERLAPPENDEN Zeiger NULL-ist, kann der Rückgabewert der Funktion fälschlicherweise darauf hinweisen, dass der Vorgang abgeschlossen wurde. Daher wird dringend empfohlen, wenn Sie ein Handle mit FILE_FLAG_OVERLAPPED erstellen und asynchrones Verhalten wünschen, sollten Sie immer eine gültige OVERLAPPED- Struktur angeben.

Das hEvent Member der angegebenen OVERLAPPED-Struktur muss ein Handle für ein manuell zurückgesetztes Ereignisobjekt 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 den Pipehandle nicht für die Synchronisierung verwenden, wenn gleichzeitige Vorgänge auf demselben Handle ausgeführt werden, da es keine Möglichkeit gibt zu wissen, welcher Vorgang abgeschlossen wurde, was dazu führte, dass der Rohrziehpunkt signalisiert wurde. Die einzige zuverlässige Technik zum Ausführen gleichzeitiger Vorgänge auf demselben Pipehandle besteht darin, eine separate OVERLAPPED- Struktur mit einem eigenen Ereignisobjekt für jeden Vorgang zu verwenden. Weitere Informationen zu Ereignisobjekten finden Sie unter Synchronisierung.

Darüber hinaus können Sie benachrichtigt werden, wenn ein überlappender Vorgang abgeschlossen wird, indem Sie die funktionen GetQueuedCompletionStatus oder GetQueuedCompletionStatusEx verwenden. In diesem Fall müssen Sie das Ereignis zum manuellen Zurücksetzen in der OVERLAPPED Struktur nicht zuweisen, und der Abschluss erfolgt auf die gleiche Weise wie ein asynchroner Lese- oder Schreibvorgang mit dem Pipehandle. Weitere Informationen finden Sie unter E/A-Vervollständigungsports.

Wenn ReadFile-, WriteFile-, TransactNamedPipe-und ConnectNamedPipe Vorgänge asynchron ausgeführt werden, tritt eine der folgenden Aktionen 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 beim Zurückgeben der Funktion nicht abgeschlossen wurde, 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 Abschlussroutinen

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