Trzy funkcje semaforów

2008-03-28 18:10

Podobno programowanie równoległe jest trudne: fakt, że kilka czynności może być wykonywanych “jednocześnie”, wprowadzać ma duże zamieszanie i komplikować życie. Nie zgadzam się! Nawet jeśli procesy lub wątki działają w tym samym czasie, to jeszcze nie jest powód do zmartwień. Prawdziwe problemy zaczynają się przecież dopiero wtedy, gdy trzeba ich działanie zsynchronizować :-)
A do tego przydają się na przykład semafory. Przy ich pomocy których można zresztą zrealizować większość popularnych mechanizmów blokowanej synchronizacji, jak choćby sekcje krytyczne. Jednak cała sztuka polega zawsze na tym, żeby użyć ich w sposób odpowiedni do danego zastosowania i nie nabawić się przy tym zagłodzenia, zakleszczenia (deadlock) lub innych “równoległych” błędów.

Semafor (kolejowy)Istnieją oczywiście tzw. schematy synchronizacji, lecz ich przydatność jest mniej więcej kilkukrotnie mniejsza niż chociażby wzorców projektowych dla programowania obiektowego. Zauważyłem jednak, że sytuacje, w których używa się semaforów (lub podobnych obiektów) można zakwalifikować do jednej z trzech grup, z których każda następna jest ugólnieniem poprzedniej:

  • Prostym i częstym przypadkiem jest wykorzystanie semafora do ochrony jakiegoś zasobu. Wówczas każdy proces (lub wątek – na tym poziomie nie ma to znaczenia) musi sprawdzić semafor przed dostępem do tego zasobu – czyli np. przed zapisem do współdzielonej pamięci.
    1. Wait (S);   // czekamy na semaforze
    2. /* praca z zasobem */
    3. Release (S);   // zwalniamy semafor

    W ten sposób tworzy się oczywiście sekcja krytyczna, bo tylko jeden proces uzyska do naszego zasobu dostęp. Wygodne jest tutaj myślenie o semaforze jako obiekcie ochraniającym zasób, a nie fragment kodu. Oczywiście na samym początku taki semafor jest zwykle opuszczony.

  • Niekiedy semafor służy do oczekiwania na spełnienie jakiegoś warunku. Weźmy na przykład serwer sieciowy, który na jednym wątku nasłuchuje połączeń (operacja blokująca), a w kolejnym wykonuje już jakieś czynności przygotowawcze dla nowego klienta. Gdy ów klient faktycznie się połączy, ten drugi wątek powinien się zająć jego obsługą, a pierwszy nadal nasłuchiwać nowych połączeń.
    Skąd ten drugi wątek we, że jest już nowy klient? Ano “wisi” on na (początkowo podniesionym) semaforze. Wątek nasłuchujący podniesie go wtedy, gdy połączenie z klientem zostanie nawiązane. Semafor sluży więc do sprawdzania pewnego warunku: czy klient jest już połączony.
  • W najbardziej ogólnej wersji semaforem kontrolujemy dostęp do różnych “miejsc” w kodzie. Każde takie miejsce można sobie wyobrazić jako pokój. Semafory będą wtedy drzwiami, stopień ich uchylenia – wartością licznika, zaś procesy będą osobami, które próbują się przez rzeczone drzwi przeciskać celem przejścia z jednego miejsca do drugiego. Wtedy wystarczy “tylko” ustalić warunki zamykania i odmykania drzwi – i już :) Rzecz w tym, że konstrukcja całego układu tych pomieszczeń nie jest w ogólności rzeczą prostą.

Bo programowanie równoległe – którego synchronizacja jest nieodłączną częścią – to jednak ciężki kawałek chleba ;]

Tags:
Author: Xion, posted under Programming »



Adding comments is disabled.

Comments are disabled.
 


© 2019 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.