Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Se även I/O-relaterade exempelprogram.
Det finns två typer av indata-/utdatasynkronisering (I/O): synkron I/O och asynkron I/O. Asynkron I/O kallas även för överlappande I/O.
I synkrona fil-I/O-startar en tråd en I/O-åtgärd och anger omedelbart ett väntetillstånd tills I/O-begäran har slutförts. En tråd som utför asynkrona fil-I/O- skickar en I/O-begäran till kerneln genom att anropa en lämplig funktion. Om begäran godkänns av kerneln fortsätter den anropande tråden att bearbeta ett annat jobb tills kerneln signalerar till tråden att I/O-åtgärden är klar. Den avbryter sedan sitt aktuella jobb och bearbetar data från I/O-åtgärden efter behov.
De två synkroniseringstyperna visas i följande bild.
I situationer där en I/O-begäran förväntas ta lång tid, till exempel en uppdatering eller säkerhetskopiering av en stor databas eller en långsam kommunikationslänk, är asynkron I/O i allmänhet ett bra sätt att optimera bearbetningseffektiviteten. För relativt snabba I/O-åtgärder kan dock arbetet med att bearbeta kernel-I/O-begäranden och kernelsignaler göra asynkrona I/O mindre fördelaktigt, särskilt om många snabba I/O-åtgärder behöver utföras. I det här fallet skulle synkron I/O vara bättre. Mekanismerna och implementeringsinformationen för hur du utför dessa uppgifter varierar beroende på vilken typ av enhetshandtag som används och programmets specifika behov. Med andra ord finns det vanligtvis flera sätt att lösa problemet.
Synkrona och asynkrona I/O-överväganden
Om en fil eller enhet öppnas för synkron I/O ( d.v.s. FILE_FLAG_OVERLAPPED inte har angetts) kan efterföljande anrop till funktioner som WriteFile blockera körningen av den anropande tråden tills någon av följande händelser inträffar:
- I/O-åtgärden slutförs (i det här exemplet en dataskrivning).
- Ett I/O-fel inträffar. (Till exempel stängs röret från den andra änden.)
- Ett fel uppstod i själva anropet (till exempel är en eller flera parametrar ogiltiga).
- En annan tråd i processen anropar funktionen CancelSynchronousIo med hjälp av den blockerade trådens trådhandtag, vilket avslutar I/O för den tråden och misslyckas med I/O-åtgärden.
- Den blockerade tråden avslutas av systemet. Själva processen avslutas till exempel, eller så anropar en annan tråd funktionen TerminateThread med hjälp av den blockerade trådens handtag. (Detta anses allmänt vara en sista utväg och inte bra programdesign.)
I vissa fall kan den här fördröjningen vara oacceptabel för programmets design och syfte, så programdesigners bör överväga att använda asynkron I/O med lämpliga trådsynkroniseringsobjekt som I/O-slutförandeportar. Mer information om trådsynkronisering finns i Om synkronisering.
En process öppnar en fil för asynkron I/O i anropet till CreateFile genom att ange flaggan FILE_FLAG_OVERLAPPED i parametern dwFlagsAndAttributes . Om FILE_FLAG_OVERLAPPED inte har angetts öppnas filen för synkron I/O. När filen har öppnats för asynkron I/O skickas en pekare till en OVERLAPPED-struktur till anropet till ReadFile och WriteFile. När du utför synkron I/O krävs inte den här strukturen i anrop till ReadFile och WriteFile.
Not
Om en fil eller enhet öppnas för asynkron I/O returnerar efterföljande anrop till funktioner som WriteFile som använder den referensen vanligtvis omedelbart men kan också bete sig synkront med avseende på blockerad körning. Mer information finns i Asynkron disk-I/O visas som synkron i Windows.
Även om CreateFile är den vanligaste funktionen att använda för att öppna filer, diskvolymer, anonyma rör och andra liknande enheter, kan I/O-åtgärder också utföras med hjälp av en typkonvertering från andra systemobjekt, till exempel en socket som skapats av socket eller accept.
Referenser till katalogobjekt hämtas genom att anropa funktionen CreateFile med attributet FILE_FLAG_BACKUP_SEMANTICS . Katalogreferenser används nästan aldrig – säkerhetskopieringsprogram är ett av de få program som vanligtvis använder dem.
När du har öppnat filobjektet för asynkron I/O måste en OVERLAPPED-struktur skapas, initieras och skickas till varje anrop till funktioner som ReadFile och WriteFile. Tänk på följande när du använder OVERLAPPED-strukturen i asynkrona läs- och skrivåtgärder:
- Frigör eller ändra inte OVERLAPPED-strukturen eller databufferten förrän alla asynkrona I/O-åtgärder till filobjektet har slutförts.
- Om du deklarerar pekaren till OVERLAPPED-strukturen som en lokal variabel ska du inte avsluta den lokala funktionen förrän alla asynkrona I/O-åtgärder till filobjektet har slutförts. Om den lokala funktionen avslutas i förtid går OVERLAPPED-strukturen utanför omfånget och den är otillgänglig för alla ReadFile - eller WriteFile-funktioner som den stöter på utanför den funktionen.
Du kan också skapa en händelse och placera handtaget i OVERLAPPED-strukturen . Väntefunktionerna kan sedan användas för att vänta tills I/O-åtgärden har slutförts genom att vänta på händelsehandtaget.
Som tidigare nämnts bör program vara försiktiga när de arbetar med ett asynkront handtag när de bestämningar om när du ska frigöra resurser som är associerade med en angiven I/O-åtgärd på handtaget. Om handtaget frigörs i förtid kan ReadFile eller WriteFile felaktigt rapportera att I/O-åtgärden är klar. Dessutom returnerar funktionen WriteFile ibland TRUE med GetLastError värde ERROR_SUCCESS, även om den använder ett asynkront handtag (som också kan returnera FALSE med ERROR_IO_PENDING). Programmerare som är vana vid synkron I/O-design släpper vanligtvis databuffertresurser i det här läget eftersom TRUE- och ERROR_SUCCESS betyder att åtgärden är klar. Men om I/O-slutförandeportar används med det här asynkrona handtaget skickas även ett slutförandepaket trots att I/O-åtgärden slutfördes omedelbart. Med andra ord, om programmet frigör resurser efter WriteFile- returnerar TRUE- med ERROR_SUCCESS utöver I/O-slutförandeporten, kommer det att ha ett dubbelfritt feltillstånd. I det här exemplet skulle rekommendationen vara att tillåta att slutförandeportrutinen är ensam ansvarig för alla frigöringsåtgärder för sådana resurser.
Systemet hanterar inte filpekaren på asynkrona handtag till filer och enheter som stödjer filpekare, det vill säga enheter som tillåter sökning. Därför måste filpositionen skickas till läs- och skrivfunktionerna i relaterade offset-dataelement i OVERLAPPED-strukturen. Mer information finns i WriteFile och ReadFile.
Filpekarens position för ett synkront handtag hanteras av systemet när data läses eller skrivs och kan även uppdateras med SetFilePointer eller SetFilePointerEx funktionen.
Ett program kan också vänta på filhandtaget för att synkronisera slutförandet av en I/O-åtgärd, men det kräver extrem försiktighet. Varje gång en I/O-åtgärd startas anger operativsystemet filhandtaget till det icke-signalerade tillståndet. Varje gång en I/O-åtgärd slutförs anger operativsystemet filhandtaget till det signalerade tillståndet. Om ett program startar två I/O-åtgärder och väntar på filhandtaget finns det därför inget sätt att avgöra vilken åtgärd som är klar när handtaget är inställt på det signalerade tillståndet. Om ett program måste utföra flera asynkrona I/O-åtgärder på en enskild fil bör det vänta på händelsehandtaget i den specifika OVERLAPPED-strukturen för varje I/O-åtgärd i stället för på det gemensamma filhandtaget.
Avbryta I/O-åtgärder
Om du vill avbryta alla väntande asynkrona I/O-åtgärder använder du antingen:
- CancelIo: Den här funktionen avbryter endast åtgärder som utfärdats av den anropande tråden för det angivna filhandtaget.
- CancelIoEx: Den här funktionen avbryter alla åtgärder som utfärdats av trådarna för det angivna filhandtaget.
Använd CancelSynchronousIo för att avbryta väntande synkrona I/O-åtgärder.
Funktionerna ReadFileEx och WriteFileEx gör det möjligt för ett program att ange en rutin att köra (se FileIOCompletionRoutine) när den asynkrona I/O-begäran har slutförts.