Delen via


Synchrone en asynchrone I/O

Zie ook I/O-gerelateerde voorbeeldtoepassingen.

Er zijn twee typen I/O-synchronisatie (input/output): synchrone I/O en asynchrone I/O. Asynchrone I/O wordt ook wel overlappende I/O genoemd.

In synchrone I/O-start een thread een I/O-bewerking en voert onmiddellijk een wachtstatus in totdat de I/O-aanvraag is voltooid. Een thread die asynchrone bestands-I/O- verzendt een I/O-aanvraag naar de kernel door een geschikte functie aan te roepen. Als de aanvraag wordt geaccepteerd door de kernel, blijft de aanroepende thread een andere taak verwerken totdat de kernel signalen aangeeft aan de thread dat de I/O-bewerking is voltooid. Vervolgens wordt de huidige taak onderbroken en worden de gegevens van de I/O-bewerking indien nodig verwerkt.

De twee synchronisatietypen worden geïllustreerd in de volgende afbeelding.

Een schermopname van een diagram dat synchrone en asynchrone i/o illustreert.

In situaties waarin een I/O-aanvraag naar verwachting veel tijd in beslag neemt, zoals een vernieuwing of back-up van een grote database of een trage communicatiekoppeling, is asynchrone I/O doorgaans een goede manier om de verwerkingsefficiëntie te optimaliseren. Voor relatief snelle I/O-bewerkingen kan de overhead van I/O-aanvragen en kernelsignalen van de kernel echter asynchrone I/O minder gunstig maken, met name als er veel snelle I/O-bewerkingen moeten worden uitgevoerd. In dit geval zou synchrone I/O beter zijn. De mechanismen en implementatiedetails van het uitvoeren van deze taken variëren, afhankelijk van het type apparaathandgreep dat wordt gebruikt en de specifieke behoeften van de toepassing. Met andere woorden, er zijn meestal meerdere manieren om het probleem op te lossen.

Synchrone en Asynchrone I/O-overwegingen

Als een bestand of apparaat wordt geopend voor synchrone I/O (dat wil gezegd , FILE_FLAG_OVERLAPPED niet is opgegeven), kunnen volgende aanroepen naar functies zoals WriteFile de uitvoering van de aanroepende thread blokkeren totdat een van de volgende gebeurtenissen plaatsvindt:

  • De I/O-bewerking wordt voltooid (in dit voorbeeld een gegevensschrijfbewerking).
  • Er treedt een I/O-fout op. (De pijp wordt bijvoorbeeld van het andere uiteinde gesloten.)
  • Er is een fout opgetreden in de aanroep zelf (bijvoorbeeld een of meer parameters zijn ongeldig).
  • Een andere thread in het proces roept de functie CancelSynchronousIo aan met behulp van de threadgreep van de geblokkeerde thread, waardoor I/O voor die thread wordt beëindigd, waardoor de I/O-bewerking mislukt.
  • De geblokkeerde thread wordt beëindigd door het systeem; Het proces zelf wordt bijvoorbeeld beëindigd of een andere thread roept de functie TerminateThread aan met behulp van de ingang van de geblokkeerde thread. (Dit wordt over het algemeen beschouwd als een laatste redmiddel en niet goed toepassingsontwerp.)

In sommige gevallen kan deze vertraging onaanvaardbaar zijn voor het ontwerp en doel van de toepassing, zodat toepassingsontwerpers overwegen asynchrone I/O te gebruiken met de juiste threadsynchronisatieobjecten zoals I/O-voltooiingspoorten. Zie Over synchronisatievoor meer informatie over threadsynchronisatie.

Een proces opent een bestand voor asynchrone I/O in de aanroep van CreateFile door de vlag FILE_FLAG_OVERLAPPED op te geven in de parameter dwFlagsAndAttributes . Als FILE_FLAG_OVERLAPPED niet is opgegeven, wordt het bestand geopend voor synchrone I/O. Wanneer het bestand is geopend voor asynchrone I/O, wordt een aanwijzer naar een OVERLAPPED-structuur doorgegeven aan de aanroep van ReadFile en WriteFile. Bij het uitvoeren van synchrone I/O is deze structuur niet vereist in aanroepen naar ReadFile- en WriteFile-.

Notitie

Als een bestand of apparaat wordt geopend voor asynchrone I/O, worden volgende aanroepen naar functies zoals WriteFile die deze handle gebruikt, doorgaans onmiddellijk geretourneerd, maar kunnen zich ook synchroon gedragen met betrekking tot geblokkeerde uitvoering. Zie Asynchrone schijf-I/O wordt als synchroon weergegeven in Windowsvoor meer informatie.

Hoewel CreateFile de meest voorkomende functie is voor het openen van bestanden, schijfvolumes, anonieme pijpen en andere vergelijkbare apparaten, kunnen I/O-bewerkingen ook worden uitgevoerd met behulp van een handle-typecast van andere systeemobjecten, zoals een socket die door de socket is gemaakt of functies accepteert.

Ingangen naar mapobjecten worden verkregen door de functie CreateFile aan te roepen met het kenmerk FILE_FLAG_BACKUP_SEMANTICS . Adreslijstingangen worden bijna nooit gebruikt: back-uptoepassingen zijn een van de weinige toepassingen die ze doorgaans gebruiken.

Nadat u het bestandsobject voor asynchrone I/O hebt geopend, moet een OVERLAPPENDE structuur correct worden gemaakt, geïnitialiseerd en doorgegeven aan elke aanroep naar functies zoals ReadFile en WriteFile. Houd rekening met het volgende bij het gebruik van de overlappende structuur in asynchrone lees- en schrijfbewerkingen:

  • Dealloceer of wijzig de OVERLAPPED-structuur of de gegevensbuffer niet totdat alle asynchrone I/O-bewerkingen voor het bestandsobject zijn voltooid.
  • Als u de aanwijzer als een lokale variabele declareert voor de structuur OVERLAPPED , sluit u de lokale functie pas af als alle asynchrone I/O-bewerkingen voor het bestandsobject zijn voltooid. Als de lokale functie voortijdig wordt afgesloten, valt de OVERLAPPED-structuur buiten het bereik en is deze niet toegankelijk voor alle ReadFile - of WriteFile-functies die buiten die functie optreden.

U kunt ook een gebeurtenis maken en de handle in de OVERLAPPED-structuur plaatsen; de wachtfuncties kunnen vervolgens worden gebruikt om te wachten tot de I/O-bewerking is voltooid door te wachten op de event-handle.

Zoals eerder vermeld, moeten toepassingen, wanneer u met een asynchrone ingang werkt, zorgvuldig omgaan met het bepalen wanneer er resources worden vrijgemaakt die zijn gekoppeld aan een opgegeven I/O-bewerking op die ingang. Als de handle voortijdig is vrijgegeven, kan ReadFile of WriteFile onjuist aangeven dat de I/O-bewerking voltooid is. Verder retourneert de functie WriteFile soms TRUE met een GetLastError-waarde van ERROR_SUCCESS, zelfs als deze gebruikmaakt van een asynchrone ingang (die ook ONWAAR kan retourneren met ERROR_IO_PENDING). Programmeurs die gewend zijn aan synchroon I/O-ontwerp, geven op dit moment meestal gegevensbufferbronnen vrij omdat TRUE en ERROR_SUCCESS aangeven dat de bewerking is voltooid. Als I/O-voltooiingspoorten worden gebruikt met deze asynchrone ingang, wordt er ook een voltooiingspakket verzonden, ook al is de I/O-bewerking onmiddellijk voltooid. Met andere woorden, als de toepassing resources vrijlaat na WriteFile retourneert TRUE- met ERROR_SUCCESS naast de I/O-voltooiingspoortroutine, heeft deze een dubbele foutvoorwaarde. In dit voorbeeld zou de aanbeveling zijn om toe te staan dat de voltooiingspoortroutine alleen verantwoordelijk is voor alle vrije bewerkingen voor dergelijke resources.

Het systeem onderhoudt de bestandsaanwijzer niet op asynchrone handlers van bestanden en apparaten die bestandsaanwijzers ondersteunen (dat wil zeggen zoekapparaten), daarom moet de bestandspositie worden doorgegeven aan de lees- en schrijffuncties in de gerelateerde offset gegevensleden van de OVERLAPPED structuur. Zie WriteFile en ReadFile voor meer informatie.

De positie van de bestandsaanwijzer voor een synchrone ingang wordt door het systeem onderhouden wanneer gegevens worden gelezen of geschreven en kunnen ook worden bijgewerkt met de functie SetFilePointer of SetFilePointerEx .

Een toepassing kan ook wachten op de bestandsgreep om de voltooiing van een I/O-bewerking te synchroniseren, maar hiervoor is extreme voorzichtigheid vereist. Telkens wanneer een I/O-bewerking wordt gestart, stelt het besturingssysteem de bestandsgreep in op de niet-ondertekende status. Telkens wanneer een I/O-bewerking wordt voltooid, stelt het besturingssysteem de bestandsgreep in op de gesignaleerde status. Als een toepassing daarom twee I/O-bewerkingen start en wacht op de bestandsgreep, is er geen manier om te bepalen welke bewerking is voltooid wanneer de ingang is ingesteld op de gesignaleerde status. Als een toepassing meerdere asynchrone I/O-bewerkingen moet uitvoeren op één bestand, moet deze wachten op de gebeurtenisgreep in de specifieke OVERLAPPED-structuur voor elke I/O-bewerking, in plaats van op de algemene bestandsingang.

I/O-bewerkingen annuleren

Als u alle asynchrone I/O-bewerkingen in behandeling wilt annuleren, gebruikt u:

  • CancelIo: Deze functie annuleert alleen bewerkingen die zijn uitgegeven door de aanroepende thread voor de opgegeven bestandsingang.
  • CancelIoEx: Met deze functie worden alle bewerkingen geannuleerd die zijn uitgegeven door de threads voor de opgegeven bestandsingang.

Gebruik CancelSynchronousIo om synchrone I/O-bewerkingen te annuleren die in behandeling zijn.

Met de functies ReadFileEx en WriteFileEx kan een toepassing een routine opgeven die moet worden uitgevoerd (zie FileIOCompletionRoutine) wanneer de asynchrone I/O-aanvraag is voltooid.

Bestand schrijven

Bestand lezen