380 likes | 501 Views
Sistemsko programiranje. X. poglavlje Asinkroni ulaz/izlaz. Ciljevi. Nakon svladavanja ovog poglavlja trebali bi znati : Opisati asinkroni I/O Preko korištenja niti, preklapajućeg (overlapped) I/O i funkcija koje se pozivaju pri završetku (completition routines)
E N D
Sistemsko programiranje X. poglavlje Asinkroni ulaz/izlaz
Ciljevi Nakon svladavanja ovog poglavlja trebali bi znati: • Opisati asinkroni I/O • Preko korištenja niti, preklapajućeg (overlapped) I/O i funkcija koje se pozivaju pri završetku (completition routines) • Odrediti koja forma je odgovarajuća za naše zahtjeve • Razumjeti prednosti asinkronog I/O • Razvijati aplikacije koje koriste asinkroni I/O
Dnevni red • 1. dio Pregled asinkronog I/O • 2. dio Preklapajući I/O • 3. dio Prošireni I/O
1. dio Pregled asinkronog I/O
Pregled • Ulaz i izlaz je uvijek sporiji od drugog procesiranja zbog određenih zastoja: • koji su uzrokovani zbog pristupa određenoj traki ili određenom sektoru na uređajima s izravnim pristupom • Diskovi i CD- i DVD-ROMovi • koji su uzrokovani zbog sporijeg transfera podataka između fizičkog uređaja i sistemske memorije • zbog čekanja na podatke koji trebaju biti zapisani u pipu od strane druge niti
Windows asinkroni I/O (1/3) • Niti i procesi • Svaka nit unutar procesa (ili u različitim procesima) izvodi normalni sinkrhoni I/O • Ali druge niti se mogu i dalje izvoditi
Windows asinkroni I/O (2/3) • Preklapajući (overlapped) I/O • Nit nastavlja izvođenje nakon izvođenja čitanja (read), pianja (write) ili neke druge I/O operacije • Nit nakon toga čeka ili na handle ili na određeni događaj kada joj je potreban rezultat izvođenja I/O operacije prije daljnjeg nastavka • Windows 9x podržava preklapajući I/O samo za serijske uređaje kao što su primjerice imenovane pipe • Datoteke na disku nisu podržane
Windows asinkroni I/O (3/3) • Funkcije koje se izvode prilikom završetka (completion routines) • Također ih zovemo i prošireni I/O ili I/O s korištenjem signala za uzbunu • Sistem izvodi određenu “funkciju pri završetku” unutar niti kada se I/O operacija dovrši • Windows 9x podržava samo serijske uređaje
2. dio Preklapajući I/O
Preklapajući I/O (1/2) • Preklapajuće strukture su moguća opcija kod 4 I/O funkcije koje mogu potencijalno blokirati sve dok se operacija ne dovrši: • ReadFile • WriteFile • TransactNamedPipe • ConnectNamedPipe
Preklapajući I/O (2/2) • Mora se postaviti FILE_FLAG_OVERLAPPED koji je dio parametra fdwAttrsAndFlags (za CreateFile) • Ili kao dio parametra fdwOpenMode (za CreateNamedPipe) • Ako se tako napravio onda je određeno da će se pipa ili datoteka koristiti samo u preklapajućem načinu rada • Primjedba: preklapajući I/O se koristi i kod Windows Socketa
Posljedice preklapajućeg I/O (1/2) • I/O operacije ne blokiraju • Trenutno se vrši povratak nakon poziva sljedećih funkcija: ReadFile WriteFile TransactNamedPipe ConnectNamedPipe • Vrijednost koju funkcija vraća ne može se koristiti kako bi pokazivala je li operacija bila uspješna ili se desila greška • I/O operacija najčešće još nije dovršena u tom trenutku
Posljedice preklapajućeg I/O (2/2) • Vraćeni broj transferiranih bajtova također nije koristan • Program može izvršiti višestruko čitanje ili pisanje na jednom te istom handle-u • Datotečni pokazivač ovdje nema smisla • Program mora biti u mogućnosti da čeka na dovršetak I/O (znači mora biti sinkroniziran s I/O operacijama) • U slučaju višestrukih operacija na jednom handle-u, program mora biti u mogućnosti odrediti koja je operacija završila • I/O operacije ne završavaju nužno u onom redosljedu u kojem su bile započete
Preklapajuće strukture (1/4) • Preklapajuća struktura: • Ukazuje na poziciju u datoteci (64 bitno) • Ukazuje na događaj koji će biti signaliziran kada operacija završi • Određuje se preko lpOverlapped parametra kod ReadFile (na primjer) • Postoje također i dva podatka tipa DWORD koje programer ne treba koristiti
Preklapajuće strukture (2/4) typedef struct _OVERLAPPED { DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; } OVERLAPPED
Preklapajuće strukture (3/4) • Pozicija u datoteci (datotečni pokazivač) mora biti postavljen u Offset i OffsetHigh • hEvent je handle od događaja • Kreiran je pozivom CreateEvent • Događaj može biti imenovan ili neimenovan, ali mora biti događaj tipa manual reset • hEvent može biti NULL, i u tom slučaju može se čekati na handle datoteke (također sinkronizacijski događaj) • Sistem signalizira završetak preko datotečnog handle-a onda kada je hEvent jednak NULL
Preklapajuće strukture (4/4) • Ovakav događaj se odmah resetira od strane sistema čim program napravi I/O poziv • Postavlja se na ne-signalizirano stanje • Kada se I/O operacija završi, događaj je signaliziran • Preklapajuća struktura se i dalje može koristiti kao alternativa za SetFilePointer • Čak i onda kada je datotečni handle sinkroni • Određena I/O operacija je jedinstveno identificirana preko kombinacije datotečnog handle-a i preklapajuće strukture
Upozorenja • Ne smije se ponovno koristiti OVERLAPPED struktura sve dok je ona pridružena nekoj I/O operaciji • Ne smije se ponovno koristiti događaj sve dok je on dio preklapajuće strukture • Ako imate više od jednog zahtjeva na preklapajući handle, koristite događaje za sinkronizaciju, radije nego datotečne handle-ove • Ako su preklapajuća struktura automatske varijable u bloku, budite sigurni da ne završite blok prije sinkronizacije s I/O operacijom
Stanja preklapajućeg I/O (1/3) • Preklapajuća ReadFile ili WriteFile operacija vraća trenutno • U većini slučajeva, I/O neće biti završen • Čitanje ili pisanje vraća FALSE • GetLastError() će vratiti ERROR_IO_PENDING • GetOverlappedResult dopušta nam da odredimo koliko je byte-ova transferirano
Stanja preklapajućeg I/O (2/3) BOOL GetOverlappedResult (HANDLE hFile, LPOVERLAPPED lpoOverlapped, LPWORD lpcbTransfer, BOOL fWait)
Stanja preklapajućeg I/O (3/3) • fWait, ako je TRUE, određuje da će funkcija GetOverlappedResult čekati sve dok određena operacija ne završi • Inače, trenutno vraća rezultat • Funkcija vraća TRUE samo ako je operacija završena • GetLastError će vratiti ERROR_IO_INCOMPLETE u slučaju vraćenog FALSE iz GetOverlappedResult • Stvarni broj transferiranih byte-ova je u parametru *lpcbTransfer
3. dio Prošireni I/O
Prošireni I/O sa završavanjem (1/2) • Radije nego da nit čeka na signal prilikom završetka, tj. na događaj ili handle, sistem može pozvati korisnički određenu “funkciju koja se izvodi pri završetku” ona kada I/O operacija bude gotova • Koristiti skupinu “proširenih” I/O funkcija koje prepoznajemo po Exsufiksu: ReadFileEx WriteFileEx
Prošireni I/O sa završavanjem (2/2) • Dodatno, koristiti se mogu i tri funkcije koje čekaju na znak za uzbunu (“alertable wait” functions): WaitForSingleObjectEx WaitForMultipleObjectsEx SleepEx • Prošireni I/O nekad zovemo i I/O sa znakom za uzbunu (“alertable I/O”)
Prošireno čitanje BOOL ReadFileEx (HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpcr)
Prošireno pisanje BOOL WriteFileEx (HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpcr)
Prošireno čitanje i pisanje (1/4) • Funkcije za prošireno čitanje i pisanje mogu se koristiti samo s otvorenim datotekama i pipama (čak i sa mailslotovima) koji su otvoreni ili kreirani s FILE_FLAG_OVERLAPPED zastavicom • Obadvije funkcije su nam poznate ali koriste dodatni parametra kako bi odredili funkciju koja će se izvršiti pri završetku • Preklapajuće strukture moraju biti predane kao parametri • Nema potrebe da se odredi član strukture hEvent
Prošireno čitanje i pisanje (2/4) • Proširene funkcije ne trebaju parametar za broj transferiranih byte-ova • Ova informacija se prenosi u funkciju koja se izvodi pri završetku, koja mora također biti uključena u program • Funkcija koja se izvršava pri završetku ima parametre: broj byte-ova, kod pogreške i preklapajuću struktur
Prošireno čitanje i pisanje (3/4) VOID WINAPI FileIOCompletionRoutine ( DWORD fdwError, DWORD cbTransferred, LPOVERLAPPED lpo) • FileIOCompletionRoutine je samo formalno napisano, nije stvarno ime, korisnik zadaje proizvoljno ime • fdwError je ograničen na 0 (uspjeh) i ERROR_HANDLE_EOF (kada čitanjem predjemo preko kraja datoteke)
Prošireno čitanje i pisanje (4/4) • Dvije stvari se moraju desiti prije nego sistem pozove fukciju koja se izvšrava pri završetku: • Aktuelna I/O operacija mora završiti • Nit koja ju poziva mora biti u stanju “čekanja na znak za uzbunu” • Kako bi se došlo u stanje čekanja na znak za uzbunu, nit mora eksplicitno pozvati jednu od tri funkcije koje rade s takvim stanjem
Funkcije koje čekaju na znak za uzbunu (1/2) DWORD WaitForSingleObjectEx ( HANDLE hObject, DWORD dwTimeOut, BOOL fAlertable) DWORD WaitForMultipleObjectsEx ( DWORD cObjects, LPHANDLE lphObjects, BOOL fWaitAll, DWORD dwTimeOut BOOL fAlertable) DWORD SleepEx (DWORD dwTimeOut, BOOL fAlertable)
Funkcije koje čekaju na znak za uzbunu (2/2) • Svaka ima zastavicu fAlertable koja se mora postaviti na vrijednost TRUE • Ove tri funkcije će završiti čim se desi nešto do sljedećeg: • Handle(ovi) je(su) signalizirani tako da zadovolje jednu od prve dvije funkcije • Bilo koja funkcija koja se poziva pri završetku unutar niti je završila • Vremenski period je završen (može biti i beskonačan infinite) • Nema događaja koji su pridruženi ReadFileEx i WriteFileEx preklapajućim strukturama • SleepEx nije pridružen sinkronizacijskom objektu
Izvršavanje funkcija koje se izvršavaju prilikom završetka (1/2) • Čim se završi proširena I/O operacija, njezina funkcija koja se izvršava prilikom završetka se stavlja u red za izvršavanje • Sve zakazane funkcije koje se izvršavaju prilikom završetka od dane niti će se izvršiti kada nit uđe u stanje čekanja na znak za uzbunu, a funkcija koja čeka na znak za uzbunu završi tek kada te spomenute funkcije završe
Izvršavanje funkcija koje se izvršavaju prilikom završetka (2/2) • SleepEx će vratiti WAIT_IO_COMPLETION ako se jedna ili više spomenutih funkcija koje su u redu za izvršavanje još uvijek izvršavaju • GetLastError će vratiti ovu istu vrijednost nakon što neka od funkcija za čekanje završi • Može se koristiti 0 vrijednost čekanja s bilo kojom funkcijom za čekanje i ona će trenutno završiti • Može se koristiti i hEvent član preklapajuće strukture kako bi prebacili bilo koju informaciju u funkciju koja se izvršava prilikom završetka
Asinkroni I/O s funkcijama koje se izvode prilikom završetka
hIn = CreateFile (... FILE_FLAG_OVERLAPPED ...); for (i = 0; i < 3; i++) { ov [i].hEvent = i + 1; ov [i].Offset = i * LSIZE; ReadFileEx (hIn, &ov [i], RDone); } /* Još koda od niti */ [3. čitanje završava] /* Još koda od niti */ [1. čitanje završava] /* Još koda od niti */ SleepEx (INFINITE); [RDone se izvršava dva puta] [Povratak iz SleepEx] /* Još koda od niti */ [2. citanje završava] /* Još koda od niti */ SleepEx (INFINITE); [RDone se izvršava jednom] /* Još koda od niti */ ExitProcess (0); RDone (... lpov ...) { /* Pokazuje da je I/O gotov */ CompleteFlag [lpov -> hEvent] = TRUE; } hEvent = 3 hEvent = 1 Red hEvent = 2
Sažetak (1/2) • Windows nam daju tri načina za izvođenje asinkronog I/O. Svaka tehnika ima svoje prednosti i jedinstvene karakteristike. Izbor je često stvar idividualan. • Korištenje niti je najopćenitija tehnika • Radi i s Windows 9x • Svaka nit je odgovorna za niz od jedne ili više sinkronizirajućih, blokirajućih I/O operacija • Svaka nit treba imati svoj handle na datoteku ili pipu
Sažetak (2/2) • Preklapajući I/O omogućava jednoj niti da izvodi asinkrone operacije na jednom handle-u datoteke • Trebamo handle događaja za svaku operaciju, radije nego nit i datotečni handle • Mora se čekati na svaku I/O operaciju da završi i onda obaviti sve potrebne operacije koje moraju čekati da I/O završi • Prošireni I/O automatski izvodi kod koji se izvodi prilikom završetka • Nisu potrebni dodatni događaji