Synchrone und überlappende Pipe-E/A
Die Funktionen ReadFile, WriteFile, TransactNamedPipeund ConnectNamedPipe können Eingabe- und Ausgabevorgänge für eine Pipe synchron oder asynchron ausführen. Wenn eine Funktion synchron ausgeführt wird, gibt sie erst dann zurück, wenn der ausgeführte Vorgang abgeschlossen ist. Dies bedeutet, dass die Ausführung des aufrufenden Threads für einen unbestimmten Zeitraum 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 nicht abgeschlossen wurde. Dadurch kann ein zeitaufwändiger Vorgang im Hintergrund ausgeführt werden, während der aufrufende Thread andere Aufgaben ausführen kann.
Mithilfe von asynchronen E/A-Vorgängen kann ein Pipeserver eine -Schleife verwenden, die die folgenden Schritte ausführt:
- Geben Sie mehrere Ereignisobjekte in einem Aufruf der Wait-Funktion an, und warten Sie, bis eines der Objekte auf den signalisierten Zustand festgelegt ist.
- Verwenden Sie den Rückgabewert der Wait-Funktion, um zu bestimmen, welcher überlappende Vorgang abgeschlossen wurde.
- Führen Sie die erforderlichen Aufgaben aus, um den abgeschlossenen Vorgang zu bereinigt und den nächsten Vorgang für dieses Pipehand handle zu initiieren. Dies kann das Starten eines weiteren überlappenden Vorgangs für dasselbe Pipehandl umfassen.
Überlappende Vorgänge ermöglichen es einer Pipe, Daten gleichzeitig zu lesen und zu schreiben, und dass ein einzelner Thread gleichzeitige E/A-Vorgänge für mehrere Pipehandles ausführen kann. Dadurch kann ein Singlethread-Pipeserver die Kommunikation mit mehreren Pipeclients effizient verarbeiten. Ein Beispiel finden Sie unter Named Pipe-Server mit überlappenden E/A-Daten.
Damit ein Pipeserver synchrone Vorgänge für die Kommunikation mit mehr als einem Client verwenden kann, muss für jeden Pipeclient ein separater Thread erstellt werden, damit ein oder mehrere Threads ausgeführt werden können, während andere Threads warten. Ein Beispiel für einen Multithreadpipeserver, der synchrone Vorgänge verwendet, finden Sie unter Multithreaded Pipe-Server.
Aktivieren eines asynchronen Vorgangs
Die Funktionen ReadFile, WriteFile, TransactNamedPipeund ConnectNamedPipe können nur asynchron ausgeführt werden, wenn Sie den überlappenden Modus für das angegebene Pipehandle aktivieren und einen gültigen Zeiger auf eine OVERLAPPED-Struktur angeben. Wenn der OVERLAPPED-Zeiger NULL ist, kann der Rückgabewert der Funktion fälschlicherweise angeben, dass der Vorgang abgeschlossen wurde. Daher wird dringend empfohlen, immer eine gültige OVERLAPPED-Struktur anzugeben, wenn Sie ein Handle mit FILE FLAG OVERLAPPED erstellen und _ _ asynchrones Verhalten wünschen.
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 wurde. Sie sollten das Pipehand handle nicht für die Synchronisierung verwenden, wenn Sie gleichzeitige Vorgänge auf demselben Handle ausführen, da es keine Möglichkeit gibt, zu wissen, welcher Vorgang die Signalisierung des Pipehandpunkts verursacht hat. Die einzige zuverlässige Technik zum Ausführen gleichzeitiger Vorgänge auf demselben Pipehandl ist die Verwendung einer separaten OVERLAPPED-Struktur mit einem eigenen Ereignisobjekt für jeden Vorgang. Weitere Informationen zu Ereignisobjekten finden Sie unter Synchronization.
Sie können auch benachrichtigt werden, wenn ein überlappende Vorgang mithilfe der Funktionen GetQueuedCompletionStatus oder GetQueuedCompletionStatusEx abgeschlossen wird. In diesem Fall müssen Sie das Manuelle Zurücksetzen-Ereignis nicht in der OVERLAPPED-Struktur zuweisen, und die Vervollständigung erfolgt für das Pipehandles auf die gleiche Weise wie bei einem asynchronen Lese- oder Schreibvorgang. Weitere Informationen finden Sie unter E/A-Abschlussports.
Wenn ReadFile-, WriteFile-, TransactNamedPipe-und ConnectNamedPipe-Vorgänge asynchron ausgeführt werden, tritt eine 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 0 (null), und die GetLastError-Funktion gibt einen anderen Wert als ERROR _ IO PENDING _ zurück.
- Wenn der Vorgang nach der Rückgabe der Funktion nicht abgeschlossen wurde, ist der Rückgabewert 0 (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-Daten zur Verfügung. 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 für die Ausführung in die Warteschlange gestellt 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 wartbaren Wartevorgang startet, indem eine der wartbaren Wartefunktionen aufgerufen wird, bei denen der Parameter fAlertable auf TRUE festgelegt ist. In einem wartebaren Wartevorgang geben die Funktionen auch zurück, wenn eine ReadFileEx- oder WriteFileEx-Vervollständigungsroutine für die Ausführung in die Warteschlange gestellt 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 ihm herstellt. Jeder Lese- oder Schreibvorgang in der Sequenz gibt eine Abschlussroutine an, und jede Vervollständigungsroutine initiiert den nächsten Schritt in der Sequenz. Ein Beispiel finden Sie unter Named Pipe-Server mit Vervollständigungsroutinen.