E:BFIFO - Extended Broadcasting FIFO
czyli Rozszerzona Kolejka Rozgłoszeniowa FIFO.
Zadanie polega na zmodyfikowaniu działania kolejki FIFO. W rzeczywistości,
utworzony zostanie nowy mechanizm, który będzie dziedziczył niektóre własności
FIFO, niektóre modyfikował, jeszcze inne rozszerzał.
Przypomnę najpierw zasadę działania kolejki FIFO, oraz jej podstawowe
własności, aby łatwiej było wskazać najważniejsze punkty modyfikacji.
- Kolejka FIFO jest mechanizmem komunikacji między niespokrewnionymi procesami.
- Do kolejki o ustalonym identyfikatorze, może być podłączonych wiele procesów,
zarówno czytający jak i piszących.
- Dane odczytywane są z kolejki w kolejności ich zapisania.
- Maksymalna ilość danych jednocześnie przechowywana w kolejce jest w Linuxie
domyślnie ustawiona na magiczną liczbę 4096 bajtów (na Intelu-rozmiar strony).
- Proces który próbuje zapisać więcej, o ile nikt nie będzie odczytywał z
kolejki, zostanie zawieszony po zapełnieniu kolejki, lub też nie zapisze
wszystkich danych (w zależności od tego, czy zapis jest ustawiona
jako blokujący). Jeżeli więc dwa procesy będą pisać do kolejki, to dane przez
nie zapisywane będą się przeplatać, gdyż mogą one być na zmianę blokowane.
(Wprawdzie zapisy krótsze niż 4096 bajtów SĄ atomowe, ale 4096 to niewiele.)
- Analogiczna sytuacja zachodzi przy czytaniu przez wiele procesów - konkurują
one o dane.
Jak widać, chociaż FIFO umożliwia komunikację wielu procesów (w odróżnieniu od
PIPE) niespokrewnionych to bez dodatkowej synchronizacji jest to właściwość
prawie bezużyteczna.
Jednak niewątpliwymi zaletą tego mechanizmu są: jego prostota oraz możliwość
przesyłania dużych ilości danych. Bardziej zaawansowane mechanizmy IPC jak
kolejki komunikatów służą do przesyłania, jak nazwa wskazuje - komunikatów
i mają nałożone duże ograniczenia, jeżeli chodzi o ilość przesyłanych danych,
zaś pamięć dzielona jest mechanizmem "surowym" jeżeli chodzi o dostęp. Jak
wynika z testów (R.Stevens "Programowanie zastosowań sieciowych w systemie
UNIX") FIFO jest najsłabszym mechanizmem pod względem efektywności i dlatego
nie zawsze warto go stosować, lecz pomińmy chwilowo ten aspekt.
TWOJE ZADANIE polega na utworzeniu nowego mechanizmu komunikacji
międzyprocesowej, którego konstrukcję oprzesz na kolejce FIFO.
Będzie to mechanizm rozgłoszeniowy (broadcasting). Mechanizm ten powinien
posiadać następujące własności:
- Umożliwia korzystanie z jednej kolejki jednocześnie wielu procesom
piszącym i wielu procesom czytającym - tak samo jak przy FIFO.
- Procesy piszące nie są zawieszane w oczekiwaniu na opróżnienie kolejki,
ich żądanie zapisu realizowane jest w całości, bez zawieszenia lub
przerwania - inaczej niż w FIFO.
- Zapewniona jest spójność zapisu, czyli strumień danych zapisany przez
proces będzie spójny bez względu na to, ile procesów jednocześnie pisze
- inaczej niż w FIFO.
- Procesy czytające przy próbie odczytu większej ilości danych niż jest
jeszcze nie odczytana dostają to, co jest - tak samo jak przy FIFO.
- Procesy czytające nie konkurują o dane. Ponieważ jest to mechanizm
rozgłoszeniowy, to każdy proces odczytuje te same dane. Każdy z nich
w dogodnym dla siebie momencie.
- Umożliwia przeskoczenie bez czytania pewnej ilości danych w kolejce.
Moje komentarze, zapewne ułatwią zrozumienie powyższych intencji:
- Oczywiste.
- Chodzi o to, żeby proces nie mógł zapełnić kolejki pisząc. Oczywiście
w pewnych rozsądnych granicach, powiedzmy kilkadziesiąt - kilkaset kB
jeżeli będziesz przechowywał te dane w pamięci i np. kilka - kilkanaście
MB jeżeli będziesz przechowywał te dane na dysku. (Sugeruję jednak
korzystanie z pamięci, by uczynić ten mechanizm szybszym od np. gniazd
w dziedzinie Unixa, które przechowują swe dane właśnie na dysku.)
Rzecz też w tym, żeby proces nie musiał czekać na opróżnienie kolejki,
ani sprawdzać czy jest miejsce w kolejce. To powinno być zmartwieniem
mechanizmu/systemu operacyjnego. Z drugiej strony zauważ, że chcemy te
same dane udostępniać wielu procesom, a nie wiemy kiedy one zechcą coś
odczytać, jak również kiedy dołączą się nowi czytelnicy. Pamięć mamy
niestety o ograniczonym rozmiarze. Toteż najstarsze komunikaty powinny
być zapewne usuwane. (Możesz ewentualnie pomyśleć o przeniesieniu ich
na dysk, byłoby to ciekawe rozszerzenie, aczkolwiek o niewielkim stopniu
trudności.) Pomyśl co z dołączającymi się czytelnikami, możesz np. zabronić
im dołączania się w pewnych momentach.
- Oczywiste. Chodzi o to, żeby dane zapisane przez proces stanowiły jeden
kawałek, nawet gdy pisze jednocześnie wiele procesów, a system je wywłaszcza.
- Oczywiste. Zrób, aby działało to dokładnie tak jak przy FIFO.
- Oczywiste. Analogiczne do np. odczytu z pliku przez wiele procesów.
- Cel tego jest następujący: być może programista będzie chciał oznaczać
pakiety, zapisane w kolejce. Wtedy proces, po przeczytaniu nagłówka
decyduje czy chce ten pakiet odczytać czy nie. Jeżeli nie, to chciałby
go przeskoczyć bez czytania - jest to zabieg czysto optymalizacyjny,
ale dodanie tej operacji nie powinno być trudne.
Testy
Gdy już uruchomisz swój program:
- Zastanów się, jak inaczej można zrealizować podobny mechanizm komunikacji.
W szczególności rozważ zwykłe kolejki, gniazda i pliki.
- Przeprowadź testy porównawcze i zastanów się, jakie są wady i zalety
stosowania każdego z tych mechanizmów
- Pomyśl także z jakich konstrukcji zastosowanych przy implementacji
wynikają słabości lub przewagi tych mechanizmów nad innymi.
- Jak sądzisz, jakie jest najlepsze zastosowanie każdego z nich?
Autor: Marcin Polak, III rok Informatyki UW