Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Asynchroniczne operacje I/O za pomocą IOCP

Podobne prezentacje


Prezentacja na temat: "Asynchroniczne operacje I/O za pomocą IOCP"— Zapis prezentacji:

1 Asynchroniczne operacje I/O za pomocą IOCP
Patrycja Brzozowska

2 I/O Completion Ports Porty zakończenia operacji I/O zapewniają wydajny model wątkowania do przetwarzania wielu asynchronicznych żądań I/O w systemie wieloprocesorowym. Gdy proces tworzy port zakończenia operacji I/O, system tworzy powiązany obiekt kolejki dla żądań, których jedynym celem jest obsługa tych żądań.

3 Jak działa IOCP ? Funkcja CreateIoCompletionPort tworzy port zakończenia I/O i kojarzy jeden lub więcej uchwytów pliku z tym portem. Gdy zakończy się asynchroniczna operacja I/O na jednym z tych uchwytów pliku, pakiet zakończenia I/O jest umieszczany w kolejce w kolejności FIFO (first-in-first-out) do powiązanego portu zakończenia operacji I/O.

4 Jednym z potężnych zastosowań tego mechanizmu jest połączenie punktu synchronizacji dla wielu uchwytów plików w jeden obiekt, chociaż istnieją również inne użyteczne aplikacje. Należy zwrócić uwagę, że podczas gdy pakiety są umieszczane w kolejce w kolejności FIFO, mogą one zostać z niej usunięte w innej kolejności.

5 Gdy uchwyt pliku jest powiązany z portem zakończenia, przekazany blok statusu nie zostanie zaktualizowany, dopóki pakiet nie zostanie usunięty z portu zakończenia. Jedynym wyjątkiem jest sytuacja, gdy pierwotna operacja powraca synchronicznie z błędem.

6 Wątek (utworzony przez główny wątek lub sam wątek główny) używa funkcji GetQueuedCompletionStatus, aby poczekać, aż pakiet zakończenia zostanie dodany do kolejki portu zakończenia operacji I/O, zamiast oczekiwać bezpośrednio na zakończenie asynchronicznych operacji I/O.

7 Wątki, które blokują ich wykonywanie na porcie zakończenia operacji I/O, są wydawane w kolejności „last-in-first-out" (LIFO), a następny pakiet ukończenia jest pobierany z kolejki FIFO portu zakończenia operacji I/O dla tego wątku. Oznacza to, że po wypuszczeniu pakietu ukończenia do wątku system zwalnia ostatni (najnowszy) wątek powiązany z tym portem, przekazując mu informację o ukończeniu najstarszego zakończenia I/O.

8 Mimo, że dowolna liczba wątków może wywołać funkcję GetQueuedCompletionStatus dla określonego portu zakończenia operacji I/O, gdy określony wątek wywoła GetQueuedCompletionStatus po raz pierwszy, zostanie powiązany z określonym portem zakończenia operacji I/O do momentu wystąpienia jednej z trzech rzeczy: wyjście wątku, wątek określa inny port zakończenia operacji I/O, wątek zamyka port zakończenia operacji I/O.  Innymi słowy, pojedynczy wątek może być powiązany z najwyżej jednym portem zakończenia I/O.

9 Gdy pakiet zakończenia jest umieszczany w kolejce do portu zakończenia I/O, system najpierw sprawdza ile wątków powiązanych z tym portem jest uruchomionych. Jeśli liczba uruchomionych wątków jest mniejsza niż wartość współbieżności , to jeden z oczekujących wątków (najnowszy) może przetwarzać pakiet zakończenia. Gdy uruchomiony wątek zakończy przetwarzanie, zwykle wywołuje ponownie GetQueuedCompletionStatus, w którym to momencie albo zwraca z następnym pakietem ukończenia albo czeka (jeśli kolejka jest pusta).

10 Zalety IOCP Wszystkie operacje I/O mogą być zarejestrowane do tego samego portu zakończenia operacji I/O. Unikamy blokowania własnych wątków oraz wątków roboczych ThreadPool. Otrzymujemy automatyczne zarządzanie wątkami, które minimalizuje przełączanie kontekstów oraz daje głównemu wątkowi więcej czasu procesora.

11 Trochę kodu... Należy utworzyć port zakończenia operacji I/O oraz zachować do niego uchwyt. //create completion code var completionPortHandle = Interop.CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, 0, 0);

12 Następnie po utworzeniu file handle dla asynchronicznej operacji I/O należy powiązać go do IOCP.
const uint Flags = 128 | (uint)1 << 30; var fileHandle = Interop.CreateFile("test.txt", (uint)1 << 31, 0, IntPtr.Zero, 3, /*FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED */ Flags, IntPtr.Zero); Interop.CreateIoCompletionPort( fileHandle, completionPortHandle, (uint)fileHandle.ToInt64(), 0);

13 Wreszcie, za każdym razem wykonując operację należy podać wywołanie zwrotne oraz uzyskać wskaźnik do struktury NativeOverlapped*. var readBuffer = new byte[1024]; uint bytesRead; var overlapped = new Overlapped { AsyncResult = new FileReadAsyncResult() ReadCallback = (bytesCount, buffer) => var contentRead = Encoding.UTF8.GetString(buffer, 0, (int)bytesCount); }, Buffer = readBuffer } }; NativeOverlapped* nativeOverlapped = overlapped.UnsafePack(null, readBuffer); Interop.ReadFile(fileHandle, readBuffer, (uint)readBuffer.Length, out bytesRead, nativeOverlapped);

14 Jak wykonywane jest wywołanie zwrotne ?
Poprzedni kod zapewnia tylko wywołanie zwrotne, ale nigdy go nie wywołuje. Jest to rola oddzielnego składnika, którego używamy do symulacji wątku portu zakończenia. var completionPortThread = new Thread(() => new IOCompletionWorker().Start(completionPortHandle)) { IsBackground = true }; completionPortThread.Start();

15 Ten komponent jest odpowiedzialny za sprawdzenie portu zakończenia dla elementów w kolejce i wywołanie powiązanego asynchronicznego wywołania zwrotnego (a także pewne czyszczenie). public class IOCompletionWorker { public unsafe void Start(IntPtr completionPort) while (true) uint bytesRead; uint completionKey; NativeOverlapped* nativeOverlapped; var result = Interop.GetQueuedCompletionStatus( completionPort, out bytesRead, out completionKey, &nativeOverlapped, uint.MaxValue); (...)

16 (...) var overlapped = Overlapped.Unpack(nativeOverlapped); if (result) { var asyncResult = ((FileReadAsyncResult)overlapped.AsyncResult); asyncResult.ReadCallback(bytesRead, asyncResult.Buffer); } else ThreadLogger.Log(Interop.GetLastError().ToString()); Overlapped.Free(nativeOverlapped);


Pobierz ppt "Asynchroniczne operacje I/O za pomocą IOCP"

Podobne prezentacje


Reklamy Google