wtorek, 16 marca 2010

Programowanie współbieżne

Poniedziałkowe laboratorium z przedmiotu "Programowanie współbieżne i rozproszone" zawsze zostawia w mojej głowie pewien mętlik. Zazwyczaj staram się wykonać jak najwięcej w czasie trwania zajęć, aby mieć mniej pracy w domu, fakt, iż jest to ostatnie laboratorium w danym dniu sprawia, że jedyną rzeczą na jakiej potrafię się skupić, jest myśl o powrocie do domowego zacisza. Ta czasowa nieprzydatność do pracy sprawia, że o wiele trudniej jest mi wpaść na prawidłowe rozwiązanie postawionego zadania, choć po dłuższej chwili namysłu okazuje się ono być całkiem banalne. Sytuacja zazwyczaj komplikuje się, gdy w głowie zaczynają pojawiać się dziesiątki pomysłów, a nie mam pewności, który jest tym właściwym.

Zabawne może wydawać się, że nie tylko ja mam wspomniany mętlik w głowie - cała grupa pozostaje z pracą do wykonania w domu. Co więcej, jeszcze ciekawiej robi się, gdy niejasności pojawiają się tuż przed terminem oddania pracy, a treść zadania mimo swojej prostoty opisu dopuszcza pozornie mnogość interpretacji. Doskonale zdaję sobie sprawę z faktu, iż sam proces planowania trwa znacznie dłużej niż kodowanie, dlatego zawsze próbuję zrobić małą burzę mózgów, w celu wyłonienia kilku najlepszych koncepcji oraz odrzucenia tych całkiem skrajnych, ale po chwili rozmowy odzywa się zmęczenie spowodowane niewyspaniem i wszystkie chęci zgłębienia tematu wnet gdzieś znikają. Wychodząc z założenia, że w programowaniu tak jak w życiu, nie zawsze liczy się fakt osiągnięcia celu, ale styl w jakim się tego dokonało, na weekend ponownie podchodzę do zadania tym razem wypoczęty i z otwartym umysłem.

Wyżej opisana historia powtarza się, co tydzień i wiem, że nie tylko ja zostawiam sobie pracę na jego koniec. Dla osób, które mimo szczerych chęci nie znalazły jednak czasu na dopracowanie swojego kodu, zamieszczam krótki opis moich pomysłów na realizację dwóch ostatnich ćwiczeń laboratoryjnych. Zaznaczam, że programy powstałe na ich bazie, zostały ocenione na ocenę bardzo dobrą, co świadczy o fakcie, iż koncepcja i wykonanie są co najmniej poprawne.

Pozornie skomplikowane zadanie, które byliśmy zobligowani wykonać na pierwszym laboratorium dotyczącym współbieżności, polegało na odwzorowaniu sytuacji mającej miejsce na parkingu. Samo rozwiązanie jest bardzo krótkie i proste, tym bardziej, że mogliśmy dopuścić do sytuacji, gdzie klienci nie honorują kolejki - najmniej zuchwały klient parkuje/wyjeżdża jako ostatni. Zuchwałość, o której piszę, to nic innego jak przydział czasu procesora, miejsce na parkingu oraz dwie bramy to zasoby, do których każdy wątek-samochód chce mieć dostęp. Jedyne wymagane na starcie programu wartości to ilość pojazdów oraz miejsc na parkingu, czas jazdy potencjalnego klienta poza parkingiem i czas jego postoju. Postanowiłem również założyć odpowiednią ilość zmian stanu pojazdów, aby generowany ruch nie był zbyt wielki, a jedynie przedstawiał mechanizm działania programu. Prostotę wykonania najważniejszych elementów tj. samochodu i obu bram ilustruje kod poniżej, na którym można dostrzec, że instrukcje informujące o zmianie stanu samochodów zawarte są w sekcjach krytycznych - w przeciwnym razie wyświetlane komunikaty nie odzwierciedlałyby chronologicznej kolejności zachodzących zdarzeń.

Klasa Parking:

Wątek:

Kolejne laboratorium było już bardziej wymagające. Tym razem zadanie polegało na odwzorowaniu sytuacji mającej miejsce na stacji benzynowej z trzema dystrybutorami. O zagłodzeniu wątków nie może być tutaj mowy - gra toczy się o dużą stawkę, brak benzyny w baku oznacza wyeliminowanie danego samochodu. Wartości liczbowe wymagane na starcie programu to maksymalna długość kolejek, ilość samochodów, ich czas tankowania oraz czas jazdy poza stacją. W przypadku zapełnienia wszystkich kolejek na stacji klient zmuszony jest do dalszej jazdy przez czas równy dwukrotności czasu tankowania, następnie może spróbować ponownie dostać się do kolejki. Samochody powinny dążyć do maksymalnego wykorzystania paliwa, dlatego założyłem, że z każdym kolejnym tankowaniem maksymalny poziom paliwa w baku się zmniejsza. Nie chciałem przecież dopuścić do sytuacji, gdzie w ruchu pozostają np. dwa samochody mające do dyspozycji całą stację dla siebie - mogłyby jeździć wtedy bez końca. Wybór do realizacji tego zadania struktury wyższego poziomu, jaką jest kolejka blokująca (w tym przypadku ArrayBlockingQueue), był dla mnie oczywisty, aczkolwiek do intensywniejszego myślenia zmusił mnie fakt, iż samochód wjeżdżający na stację, powinien wybrać najkrótszą kolejkę. Pierwszym pomysłem było wykorzystanie metod kolejek blokujących w sekcji krytycznej, która zlicza poziom ich zapełnienia i na żądanie klienta wybiera najkrótszą. Następnym krokiem przy założeniu, że pojazd został już przyporządkowany do jednej z kolejek, jest sprawdzenie, czy samochód zgłaszający chęć skorzystania z dystrybutora, jest pojazdem znajdującym się na czele kolejki - tu przychodzi z pomocą metoda peek(), która zwraca element z kolejki bez usuwania go. W przypadku zgodności wykonana zostaje metoda poll() (usuwa samochód z kolejki), po czym dany samochód uzyskuje dostęp do dystrybutora blokując go jednocześnie na czas użytkowania. W przeciwnym przypadku - stwierdzenia niezgodności - zostaje ponowiona weryfikacja, czy samochód zgłaszający chęć skorzystania z dystrybutora, jest pojazdem znajdującym się na czele kolejki. Pomysł ten sprawia wrażenie akceptowalnego, ale czy nie dałoby się zrobić tego subtelniej? Jestem otwarty na wszelkie sugestie.

2 komentarze:

Paweł Badeński pisze...

jeśli chodzi o wstawki kodu polecam http://code.google.com/p/syntaxhighlighter/ :)

Marek Szpak pisze...

Dzięki, w wolnej chwili zapoznam się bliżej z tym projektem :)