Synchronisierung und überlappende Eingabe und Ausgabe
Sie können synchrone oder asynchrone (auch als überlappende) E/A-Vorgänge für Dateien, benannte Rohre und serielle Kommunikationsgeräte ausführen. Die WriteFile, ReadFile, DeviceIoControl, WaitCommEvent, ConnectNamedPipeund TransactNamedPipe- Funktionen können synchron oder asynchron ausgeführt werden. Die funktionen ReadFileEx und WriteFileEx können nur asynchron ausgeführt werden.
Wenn eine Funktion synchron ausgeführt wird, wird sie erst zurückgegeben, wenn der Vorgang abgeschlossen wurde. 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. Funktionen, die für überlappenden Vorgang aufgerufen werden, können sofort zurückgegeben werden, auch wenn der Vorgang nicht abgeschlossen wurde. Dadurch kann ein zeitaufwändiger E/A-Vorgang im Hintergrund ausgeführt werden, während der aufrufende Thread frei ist, andere Aufgaben auszuführen. Beispielsweise kann ein einzelner Thread gleichzeitige E/A-Vorgänge für verschiedene Handles oder sogar gleichzeitige Lese- und Schreibvorgänge auf demselben Handle ausführen.
Um die Ausführung mit dem Abschluss des überlappenden Vorgangs zu synchronisieren, verwendet der aufrufende Thread die GetOverlappedResult-Funktion, die GetOverlappedResultEx--Funktion oder eine der Wartefunktionen, um zu bestimmen, wann der überlappende Vorgang abgeschlossen wurde. Sie können auch das HasOverlappedIoCompleted Makro verwenden, um den Abschluss abzufragen.
Um alle ausstehenden asynchronen E/A-Vorgänge abzubrechen, verwenden Sie die CancelIoEx--Funktion, und stellen Sie eine OVERLAPPED--Struktur bereit, die die Anforderung angibt, abzubrechen. Verwenden Sie die CancelIo--Funktion, um ausstehende asynchrone E/A-Vorgänge abzubrechen, die vom aufrufenden Thread für das angegebene Dateihandle ausgegeben werden.
Überlappende Vorgänge erfordern eine Datei, ein benanntes Pipe- oder Kommunikationsgerät, das mit dem FILE_FLAG_OVERLAPPED Flag erstellt wurde. Wenn ein Thread eine Funktion aufruft (z. B. die ReadFile--Funktion), um einen überlappenden Vorgang auszuführen, muss der aufrufende Thread einen Zeiger auf eine ÜBERLAPPENDE Struktur angeben. (Wenn dieser Zeiger NULL-ist, weist der Rückgabewert der Funktion möglicherweise falsch darauf hin, dass der Vorgang abgeschlossen ist.) Alle Elemente der OVERLAPPED-Struktur müssen auf Null initialisiert werden, es sei denn, ein Ereignis wird verwendet, um den Abschluss eines E/A-Vorgangs zu signalisieren. Wenn ein Ereignis verwendet wird, gibt das hEvent Member der OVERLAPPED- Struktur ein Handle für das zugeordnete Ereignisobjekt an. Das System legt den Status des Ereignisobjekts auf kein Signal fest, wenn ein Aufruf der E/A-Funktion zurückgegeben wird, bevor der Vorgang abgeschlossen wurde. Das System legt den Zustand des Ereignisobjekts fest, das signalisiert wird, wenn der Vorgang abgeschlossen wurde. Ein Ereignis wird nur benötigt, wenn gleichzeitig mehrere ausstehende E/A-Vorgänge vorhanden sind. Wenn ein Ereignis nicht verwendet wird, signalisiert jeder abgeschlossene E/A-Vorgang die Datei, das benannte Pipe- oder Kommunikationsgerät.
Wenn eine Funktion aufgerufen wird, um einen überlappenden Vorgang auszuführen, kann der Vorgang abgeschlossen werden, bevor die Funktion zurückgegeben wird. In diesem Fall werden die Ergebnisse so behandelt, als ob der Vorgang synchron ausgeführt wurde. Wenn der Vorgang jedoch nicht abgeschlossen wurde, ist der Rückgabewert der Funktion FALSE, und die GetLastError Funktion gibt ERROR_IO_PENDINGzurück.
Ein Thread kann überlappende Vorgänge mit einer von zwei Methoden verwalten:
- Verwenden Sie die GetOverlappedResult oder GetOverlappedResultEx--Funktion, um zu warten, bis der überlappende Vorgang abgeschlossen ist. Wenn GetOverlappedResultEx- verwendet wird, kann der aufrufende Thread ein Timeout für den überlappenden Vorgang angeben oder eine warnbare Wartezeit ausführen.
- Geben Sie ein Handle für das OVERLAPPED-Ereignisobjekt der manuellen Zurücksetzungsstruktur in einer der Wartefunktionen an, und rufen Sie nach dem Zurückgeben der Wait-Funktion GetOverlappedResult oder GetOverlappedResultExauf. Die Funktion gibt die Ergebnisse des abgeschlossenen überlappenden Vorgangs zurück, und für Funktionen, in denen solche Informationen geeignet sind, meldet sie die tatsächliche Anzahl der Bytes, die übertragen wurden.
Beim Ausführen mehrerer gleichzeitig überlappender Vorgänge in einem einzelnen Thread muss der aufrufende Thread eine ÜBERLAPPENDE Struktur für jeden Vorgang angeben. Jede ÜBERLAPPENDE Struktur muss ein Handle für ein anderes ereignisgesteuertes Ereignisobjekt angeben. Um zu warten, bis eine der überlappenden Vorgänge abgeschlossen ist, gibt der Thread alle manuell zurückgesetzten Ereignishandles als Wartezeitkriterien in einer der Mehrfachobjekt-Wait-Funktionenan. Der Rückgabewert der Wait-Funktion mit mehreren Objekten gibt an, welches Ereignisobjekt manuell zurückgesetzt wurde, sodass der Thread bestimmen kann, welcher überlappende Vorgang den Wartevorgang abgeschlossen hat.
Es ist sicherer, ein separates Ereignisobjekt für jeden überlappenden Vorgang zu verwenden, anstatt kein Ereignisobjekt anzugeben oder dasselbe Ereignisobjekt für mehrere Vorgänge wiederzuverwenden. Wenn kein Ereignisobjekt in der OVERLAPPED-Struktur angegeben ist, signalisiert das System den Zustand der Datei, des benannten Rohrs oder des Kommunikationsgeräts, wenn der überlappende Vorgang abgeschlossen wurde. Daher können Sie diese Handles als Synchronisierungsobjekte in einer Wartefunktion angeben, obwohl deren Verwendung für diesen Zweck schwierig zu verwalten sein kann, da beim Ausführen gleichzeitig überlappender Vorgänge auf derselben Datei, benannten Pipe oder Kommunikationsgerät keine Möglichkeit besteht, zu wissen, welcher Vorgang den Zustand des Objekts signalisiert hat.
Ein Thread sollte ein Ereignis nicht wiederverwenden, wobei davon ausgegangen wird, dass das Ereignis nur durch den überlappenden Vorgang dieses Threads signalisiert wird. Ein Ereignis wird im selben Thread wie der überlappende Vorgang signalisiert, der abgeschlossen wird. Die Verwendung desselben Ereignisses in mehreren Threads kann zu einer Racebedingung führen, in der das Ereignis für den Thread richtig signalisiert wird, dessen Vorgang zuerst und vorzeitig für andere Threads mit diesem Ereignis abgeschlossen ist. Wenn der nächste überlappende Vorgang abgeschlossen ist, wird das Ereignis für alle Threads, die dieses Ereignis verwenden, erneut signalisiert, und so weiter, bis alle überlappenden Vorgänge abgeschlossen sind.
Beispiele, die die Verwendung überlappender Vorgänge, Abschlussroutinen und der GetOverlappedResult--Funktion veranschaulichen, finden Sie unter Using Pipes.
Windows Vista, Windows Server 2003 und Windows XP:
Achten Sie beim Wiederverwenden ÜBERLAPPENden Strukturen. Wenn ÜBERLAPPENDE Strukturen für mehrere Threads wiederverwendet werden und GetOverlappedResult aufgerufen wird, wobei der bWait Parameter auf TRUEfestgelegt ist, muss der aufrufende Thread sicherstellen, dass das zugeordnete Ereignis signalisiert wird, bevor die Struktur erneut verwendet wird. Dies kann mithilfe der WaitForSingleObject-Funktion erreicht werden, nachdem GetOverlappedResult- aufgerufen wurde, um zu erzwingen, dass der Thread wartet, bis der Vorgang abgeschlossen ist. Beachten Sie, dass das Ereignisobjekt ein ereignisgesteuertes Ereignisobjekt sein muss. Wenn ein Autoreset-Ereignisobjekt verwendet wird, bewirkt das Aufrufen GetOverlappedResult- mit dem parameter bWait auf TRUE festgelegt, dass die Funktion unbegrenzt blockiert wird. Dieses Verhalten wurde ab Windows 7 und Windows Server 2008 R2 für Anwendungen geändert, die Windows 7 als unterstütztes Betriebssystem im Anwendungsmanifest angeben. Weitere Informationen finden Sie unter Anwendungsmanifests.
Verwandte Themen