opracowane zagadnienia 2011

background image

programowanie

współbieżne

hahahaha rozwalilo mnie to

Podstawowe pojęcia współbieżności

Bezpieczeństwo
Żywotność
Blokada
Zagłodzenie
Uczciwość
Skutki stosowania współbieżności

Wstęp do procesów

Stany procesów
Deskryptor procesu

Zawartość deskryptora procesu

Fazy wykonania procesu
Atrybuty procesu
Dziedziczenie atrybutów

Procesy Posix

Tworzenie procesów

background image

Funkcje
Makra
Akcje przy zakończeniu procesu

Pliki i funkcje dostępu do pliku
Łącza nienazwane

Wykorzystanie
Funkcje

Łącza nazwane

Wykorzystanie
Funkcja mkfifo
Funkcja select

Pamięć dzielona

Komunikacja przez wspólną pamięć w standardzie POSIX
Funkcje

Kolejki komunikatów

Kolejki komunikatów POSIX i zastosowania
Funkcje

Synchronizacja

Wzajemne wykluczanie
Operacje atomowe
Sekcja krytyczna
Warunki poprawnego rozwiązania sekcji krytycznej
Niesystemowe i systemowe metody ochrony sekcji krytycznej
Sprzętowa ochrona sekcji krytycznej

Semafory i ich zastosowanie

Ochrona sekcji krytycznej
Semafory nienazwane i nazwane POSIX
Funkcje

Monitory

Definicja
Zastosowanie
Oczekiwanie wewnątrz monitora
Zmienne warunkowe
Funkcje
Implementacja semafora poprzez monitor

Wątki

Wątki pojęcie i zasoby
Tworzenie
Synchronizacja
Funkcje
Mutexy
Zmienne warunkowe
Blokady czytelników i pisarzy
Wirujące blokady

Inwersja priorytetów

Ochrona przed inwersją
Metody dziedziczenia priorytetów

background image

Metody pułapu priorytetów

Gniazdka

Interfejs gniazd
Funkcje
Serwer sekwencyjny
Serwer współbieżny

Sygnały

Sygnały i ich obsługa
Instalacja handlera sygnału
Blokowanie sygnałów
Sygnały a wątki

Timery

Posługiwanie się timerem

RPC

Zdalne wykonywanie procedur RPC
DO ZROBIENIA
Podstawowe pojęcia
Wiązanie dynamiczne
Język opisu interfejsu IDL
Tworzenie aplikacji w standardzie Sun RPC

Linda

System Linda
Linda – własności
Wspiera tworzenie aplikacji równoległych typu zarządca – wykonawca
Kod niezależny od liczby procesów wykonawczych
Wspiera równoległość i komunikację międzyprocesową
Nakładanie się komunikacji i obliczeń
Nadaje się do systemów heterogenicznych (składających się z różnych maszyn)
Przestrzeń krotek
Operacje
Wyrażanie operacji synchronizacyjnych i komunikacyjnych

Problem producenta i konsumenta, czytelników i pisarzy

Rozwiązanie za pomocą semaforów
Rozwiązanie za pomocą monitorów
Rozwiązanie za pomocą zmiennych warunkowych
Rozwiązanie za pomocą mechanizmów języka Linda

Podstawowe pojęcia współbieżności

Procesy sekwencyjne - najpierw wykonuje się jeden, potem drugi.

Procesy współbieżne - jeden z procesów rozpoczyna się przed zakończeniem
drugiego.

Procesy równoległe - j/w, ale wykonywane są na oddzielnych procesorach.

background image

Bezpieczeństwo

Aplikacja jest bezpieczna, jeśli w przypadku działania współbieżengo nie wykrzaczy się.
Tzn:

Wszystkie sekcje krytyczne są prawidłowo zabezpieczone - jeśli nie, to wyniki mogą
być nieprawidłowe (jeden wątek nadpisujący dane innego (czyli wyścigi) itp),

Aplikacja na pewno się nie

zablokuje

.

Można też powiedzieć, że aplikacja jest bezpieczna, jeśli nie zaprzestanie obsługi zleceń i
będzie je zawsze realizowała w prawidłowy sposób.

Żywotność

Gwarancja, że każda żądana akcja musi się kiedyś wykonać. Przykładowo, każdy klient
podłączany do serwera zostanie (prędzej czy później) obsłużony.

Blokada

Zwana również

zakleszczeniem

. Generalnie chodzi o to, że każdy zablokowany proces

czeka na inny zablokowany proces, następuje błędne koło i żaden z nich się nie odblokuje.

Zagłodzenie

Zagłodzenie występuje gdy procesowi cały czas odmawia się dostępu do zasobów których
ten potrzebuje by wykonać zlecone mu zadanie.

Zagłodzenie procesu

- na przykład, jeśli mamy dużo procesów o wysokim priorytecie i

planista systemowy nie jest na to przygotowany, to procesy o niskim priorytecie mogą
nigdy nie dopchać się do zasobów, których potrzebują.

Uczciwość

Procesy żądające obsługi są traktowane zgodnie ze swoimi priorytetami lub jednakowo.
Rodzaje uczciwości:

Uczciwość słaba – jeżeli proces nieprzerwanie zgłasza żądanie to kiedyś będzie ono
obsłużone.

Uczciwość mocna – jeśli proces zgłasza żądanie nieskończenie wiele razy to w
końcu zostanie ono obsłużone.

Uczciwość liniowa – jeśli proces zgłasza żądanie będzie ono obsłużone zanim
dowolny inny proces będzie obsłużony więcej niż raz.

Uczciwość typu FIFO – żądania procesów są obsługiwane zgodnie z kolejnością ich
zgłaszania. (FIFO – ang. First-In First-Out)

Skutki stosowania współbieżności

Korzyści wynikające z zastosowania współbieżności:

1. Polepszenie wykorzystania zasobów. Gdy jakiś proces czeka na niedostępny w

background image

danej chwili zasób, procesor może wykonywać inny proces.

background image

2. Podział zadania na procesy umożliwia wykonywanie ich na oddzielnych maszynach.

Prowadzi to do zrównoleglenia przetwarzania.

3. Podział dużego zadania na wiele mniejszych komunikujących się procesów

prowadzi do dekompozycji problemu. Przez co ułatwia ich implementację,
uruchamianie i testowanie przez wielu niezależnych programistów.


Trudności powstające przy implementacji aplikacji współbieżnych:

problem sekcji krytycznej

problem synchronizacji procesów

problem zakleszczenia


Procesy tworzące aplikację nie działają w izolacji. Muszą jakoś ze sobą współpracować co
prowadzi do:
- Konieczności wzajemnej wymiany informacji - komunikacja międzyprocesowa.
- Zapewnienia określonej kolejności wykonania pewnych akcji - problem synchronizacji.

Przedmiot programowania współbieżnego
Metodologia tworzenia aplikacji składających się z wielu komunikujących się i dzielących
zasoby procesów współbieżnych.

Wstęp do procesów

Stany procesów

Wyróżniamy 3

stany procesów

:

Wykonywany - proces, który aktualnie się wykonuje. Tutaj nie ma wiele do
dyskusji.

Gotowy - proces, który aktualnie się nie wykonuje. Mógłby, ale brakuje dla niego
zasobów (np. mamy tylko jeden procesor, więc nie może wykonywać się więcej niż
jeden proces jednocześnie).

Zablokowany - Proces, który na coś czeka, np. na zakończenie wątku
(pthread_join()), podprocesu (wait()), dostępu do sprzętu itp.

Zombie - Proces, który się zakończył, ale jego proces macierzysty nie wykonał
funkcji wait()

background image

Jak widać na powyższym rysunku, proces wykonywany może zmienić stan na gotowy i
odwrotnie (głównie ze względu na planistę systemowego, przydział czasu procesora itp).
Ale już zablokować może się tylko gdy jest wykonywany (no bo w sumie ciężko, żeby
wywołał wait() w trakcie gotowości), a z zablokowanego może stać się tylko gotowy.
Proces może zakończyć się w każdej chwili, a po uruchomieniu przechodzi od razu do
stanu gotowości.

Deskryptor procesu

(ang. process descriptor) rekord w którym system operacyjny utrzymuje wszystkie
informacje niezbędne do zarządzania procesem.

Zawartość deskryptora procesu

PID

Stan procesu

Wskaźnik na poprzedni i następny deskryptor

Wskaźnik do poprzedniego i następnego procesu w kolejce (zablokowanych,
gotowych itp)

Informacje o szeregowaniu (priorytet itp)

Informacje o obsłudze sygnałów (sygnały dostarczane, zablokowane)

Informacje o hierarchii procesów (proces macierzysty, procesy potomne)

Kontekst procesu (rejestry)

Informacje o zużytym czasie procesora

Nazwa pliku, z którego proces został stworzony

UID, GID, EUID, EGID

Rozmiar segmentu kodu, danych i stosu

Położenie segmentu kodu, danych i stosu

Informacje o stronach zajmowanych przez proces

background image

Katalog bieżący i macierzysty

Informacja o terminalu sterującym

UMASK

- wzorzec uprawnień dla nowych plików

Wskaźnik na tablicę deskryptorów plików otwartych

Fazy wykonania procesu

1. Tworzenie :

Alokacja deskryptora procesu, przydział PID
Ustalenie zmiennych otoczenia – zwykle dziedziczone z procesu macierzystego

2. Ładowanie

Załadowanie segmentu kodu i danych oraz inicjacji stosu. Ładowanie wykonywane

jest przez oddzielny watek ładujący aby nie blokować administratora procesu Proc.

3. Faza wykonania

Po zaladowaniu nowy proces jest umieszczany w kolejce procesów gotowych,

uruchamiany i zaczyna wspólzawodniczyc o zasoby.

4. Faza zakonczenia

Zakończenie procesu może być zainicjowane przez sam proces – gdy wykona on
funkcje exit, lub poprzez wysłany z zewnątrz sygnał. Zakonczenie sklada sie z

dwu etapów.

a. Zwolnienie zasobów - proces zwalnia wszystkie zajmowane zasoby jak

pamiec, nazwy, itd. oraz likwiduje interakcje z innymi procesami. Po
wykonaniu tej fazy zajmuje tylko deskryptor.

b. Zawiadomienie procesu macierzystego o zakończeniu. Dopóki proces

macierzysty nie wykona funkcji wait lub waitpid konczony proces pozostaje
w stanie „zombie”. Aby uniknac pozostawania procesów w stanie „zombie”
mozna ustawic reakcje na sygnal SIGCHLD w funkcji signal na SIG_IGN.

Atrybuty procesu

PID - identyfikator procesu

PPID - PID procesu macierzystego

UID - identyfikator użytkownika

GID - identyfikator grupy użytkownika

SID - identyfikator sesji

PGRP - identyfikator grupy procesów

priorytet procesu

CWD - katalog bieżący

katalog główny

otoczenie procesu

Dziedziczenie atrybutów

Proces potomny dziedziczy większość atrybutów procesu macierzystego, ale ma swoje PID,
PPID oraz własne kopie deskryptorów otwartych plików.

[

źródło

]

background image

Procesy Posix

Tworzenie procesów

fork()

tworzy kopię bieżącego procesu. Od procesu macierzystego różni się PIDem,

Parent PIDem, a dla wszystkich otwartych plików w procesie macierzystym proces
potomny otrzymuje kopie ich deskryptorów (zamiast korzystać z deskryptorów
utworzonych przez proces macierzysty).
Funkcja fork() tworzy deskryptor nowego procesu oraz kopię segmentu danych i stosu.

Funkcje

fork()

- Utworzenie kopii procesu bieżącego

exec() - Zastąpienie procesu bieżącego innym procesem – rodzina funkcji.

wait(), waitpid() - Czekanie na zakończenie procesu

exit() - Zakończenie procesu

spawn() - Utworzenie procesu potomnego – rodzina funkcji.

Makra

WEXITSTATUS - Zwraca kod powrotu y przekazany przez funkcję exit(y) z procesu
potomnego

WTERMSIG - jeśli proces był zakończony przez sygnał, to zwraca numer sygnału

WIFEXITED - jeśli proces potomny był zakończony normalnie, to zwraca > 0

WIFSIGNALED - zwraca >0, jeśli proces potomny został zakończony przez nie
obsłużony sygnał

Akcje przy zakończeniu procesu

Należy zakończyć komunikację z innymi procesami

Należy zwolnić zajmowane zasoby

Należy zaczekać na zakończenie procesów potomnych (bo inaczej są one
adoptowane przez init)

1. Zamykane są otwarte pliki i strumienie
2. Najmłotszy bajt z kodu powrotu x jest przekazywany do zmiennej odczytywanej

przez funkcję wait() w procesie macierzystym. Kod powrotu jest zapamiętywany

w deskryptorze.

3. Jeśli proces macierzysty wywołał wait() albo waitpid(), to zostaje on

odblokowany a deskryptor jest usuwany

4. Jeśli jednak nie wywołał tych funkcji, to proces potomny przechodzi do stanu

zombie, a kod powrotu czeka sobie w deskryptorze.

5. Proces macierzysty otrzymuje sygnał SIGCHLD.

background image

Pliki i funkcje dostępu do pliku

open()

- funkcja otwierająca plik (lub np. urządzenie będące plikiem). Potrafi

utworzyć plik, jeśli takowy nie istnieje, ale to zależy od ustawień oflag. Funkcja

zwraca deskryptor pliku (uchwyt), którego używamy do identyfikacji pliku.

creat()

- funkcja tworząca nowy plik. W argumencie podajemy nazwę pliku i

atrybuty (prawa dostępu). Funkcja, podobnie jak open(), zwraca deskryptor pliku.

read()

- Za parametr bierze deskryptor pliku, bufor docelowy i ilość bajtów do

odczytu, a co robi z tą wiedzą to już można się domyśleć. Czyta w bieżącej pozycji
w pliku, jeśli nam to nie pasuje to pozostaje

lseek()

.

write()

- Parametry to deskryptor pliku, bufor zawierający dane do zapisu i ilość

bajtów do zapisania. Analogicznie jak read(), ale na odwrót.

close()

zamyka plik.

lseek()

- Pozwala zmieniać obecną pozycję w pliku. Argumenty to deskryptor

pliku, offset stanowiący o ile mamy się przesunąć i flagę która decyduje, czy
przesuwamy się względem bieżącej pozycji, początku lub końca pliku.

{,f,l}stat()

- Zwraca informacje o pliku (inode, uprawnienia itp).

fcntl()

- Zmienia atrybuty pliku.

unlink()

, remove() - usuwa plik

dup()

, dup2() - duplikuje deskryptor pliku. Można robić takie rzeczy jak np.

czitować program żeby myślał, że pisze na stdout a w rzeczywistości pisałby do
pliku.

Łącza nienazwane

Wykorzystanie

Prosta komunikacja pomiędzy procesem macierzystym i potomnym, nie ma możliwości
wymiany deskryptora pliku, w którym znajduje się łącze nienazwane inaczej niż gdy oba
procesy są w relacji macierzysty/potomny. Ten kanał komunikacji jest jednostronny dla
danego procesu, tzn np. macierzysty tylko czyta, a potomny tylko pisze.

1. Tworzymy łącze za pomocą funkcji pipe(), której parametrem jest wskaźnik na

dwuelementową tablicę int - w niej znajdą się deskryptory.

2. fork()ujemy sobie program

3. W procesie potomnym zamykamy nieużywany deskryptor za pomocą close(), np

jeśli tylko będziemy pisać, to zamykamy deskryptor do pisania (close(fd[1])),

po czym czytamy/zapisujemy jak z normalnym plikiem

4. W procesie macierzystym analogicznie
5. Na końcu robimy close() na pozostałych deskryptorach, z których korzystaliśmy i

to tyle

background image

Funkcje

pipe()

- tworzy łącze nienazwane.

open()

, read(), write(), close() - jak w przypadku

plików

. Uwaga: nie

używamy open() w przypadku łącz nienazwanych, bo nie mamy pliku, który

chcemy otworzyć - zamiast tego korzystamy z pipe().

flock()

- blokuje plik, pozwalając na synchronizację dostępu do niego pomiędzy

kilkoma procesami.

fileno()

- zwraca deskryptor pliku dla argumentu FILE*.

Łącza nazwane

Wykorzystanie

Łącza nazwane mogą być używane przez niepowiązane ze sobą procesy. Są to po
prostu specjalne pliki, które są normalnie dostępne w systemie plików. Pliki te giną po
wyłączeniu komputera.

1. Tworzymy plik FIFO za pomocą mkfifo(),

2. Otwieramy plik poprzez open(),

3. read() i write() jak kto potrzebuje,

4. tradycyjne close().

Funkcja mkfifo

Strona w manie

- tworzy łącze nazwane, jako argument przyjmuje nazwę pliku FIFO oraz

prawa dostępu do pliku.

int mkfifo(char * path, mode_t mode)

path -

Nazwa pliku FIFO (ze ścieżką)

mode

- Prawa dostępu do pliku .

Funkcja zwraca: 0 – sukces, -1 – błąd.

Funkcja select

Funkcja ta blokuje bieżący proces do momentu, kiedy dany deskryptor stanie się gotowy
albo wystąpi błąd. Można mu ustawić timeout, czyli czas, po którym funkcja daje sobie
spokój, dłużej nie czeka tylko zwraca błąd.
Tutaj nie ma wiele do mówienia, lepiej

przeczytać stronę manuala

.

Pamięć dzielona

background image

Komunikacja przez wspólną pamięć w standardzie
POSIX

1. Alokujemy pamięć dzieloną poprzez funkcję shm_open(), w atrybutach której

znajduje się nazwa segmentu pamięci dzielonej i jej atrybuty, i która zwraca
deskryptor pliku,

2. Poprzez

ltrunc()

lub

ftruncate()

ustalamy obszar zajmowanej pamięci,

3. Używając mmap() inicjujemy zmienną w pamięci dzielonej, zwykle ładując tam

wcześniej zdefiniowaną strukturę; jako wynik owej funkcji otrzymujemy wskaźnik
do zmiennej

4. Korzystamy sobie ze struktury normalnie
5. Zwalniamy nazwę pamięci dzielonej za pomocą shm_unlink(nazwa).

Przykład:

https://bitbucket.org/fleg/glupotki/src/831bc7d2d314/wspolbiezne/lab5/semafory/

main.c

Funkcje

shm_open()

shm_unlink()

ftruncate()

mmap()

Kolejki komunikatów

Kolejki komunikatów POSIX i zastosowania

Są widziane jako plik specjalny

Komunikaty w kolejce zachowują swoją strukturę; są separowane. Nie jest już
tak, jak w FIFO, gdzie po prostu czytamy tyle a tyle bajtów. Komunikaty w kolejce
mogą być różnej długości.

Komunikaty w kolejce mogą mieć różne priorytety.

Kolejki komunikatów są wygodne, gdy:

Proces wysyłający komunikaty nie może zostać wstrzymany,

Proces wysyłający nie wymaga informacji zwrotnej od adresata,

Konieczne jest przekazywanie danych od producenta do konsumenta.

Korzystanie z kolejki w praktyce: (

kod źródłowy

)

1. Za pomocą struktury mq_attr ustawiamy opcje kolejki

2. Tworzymy/otwieramy kolejkę komunikatów za pomocą funkcji mq_open(), która

za parametry przyjmuje nazwę kolejki, tryb otwarcia (zapis/odczyt), uprawnienia i
wskaźnik na strukturę z punktu 1, a zwraca mqd_t,

3. operujemy sobie na kolejce za pomocą mq_send() lub mq_receive(),

4. zamykamy kolejkę za pomocą mq_close(),

background image

5. kasujemy kolejkę za pomocą mq_unlink(). Kasowanie to nie powinno

spowodować problemów, jeśli jakiś inny proces aktualnie korzysta z kolejek
(w końcu nie interesuje go ścieżka do pliku itp, a licznik otwarcia nadal będzie
większy od 0), ale to tylko moje przemyślenie.

Funkcje

mq_open

mq_receive

mq_send

mq_attr

mq_notify

Synchronizacja

Wzajemne wykluczanie

Wzajemne wykluczanie - wymaganie aby ciąg operacji na pewnym zasobie (zwykle
pamięci) był wykonany w trybie wyłącznym przez tylko jeden z potencjalnie wielu
procesów.

Operacje atomowe

Operacje, które nie mogą zostać przerwane, np. przez przełączenie procesu.

Sekcja krytyczna

Sekcja, która może być wykonywana równolegle/współbieżnie przez tylko jeden proces.

Warunki poprawnego rozwiązania sekcji krytycznej

Rozwiązanie problemu wzajemnego wykluczania musi spełniać następujące warunki:

1. W sekcji krytycznej może być tylko jeden proces to znaczy instrukcje z sekcji

krytycznej nie mogą być przeplatane.

2. Nie można czynić żadnych założeń co do względnych szybkości wykonywania

procesów.

3. Proces może się zatrzymać w sekcji lokalnej nie może natomiast w sekcji

krytycznej. Zatrzymanie procesu w sekcji lokalnej nie może blokować innym
procesom wejścia do sekcji krytycznej.

4. Każdy z procesów musi w końcu wejść do sekcji krytycznej.

A nie chodzi

o to

?

Niesystemowe i systemowe metody ochrony sekcji

background image

krytycznej

DO UZUPEŁNIENIA

Systemowe:

1. Blokowanie przerwań
2. Metoda zmiennej blokującej (nieprawidłowa)


Niesystemowe:

1. Wirujące blokady (ang. Spin Locks) wykorzystujące sprzętowe wsparcie w postaci

instrukcji sprawdź i przypisz oraz zamień. Stosuje się je do synchronizacji wątków
ze względu na mały narzut operacji systemowych.

2. Blokowanie przerwań – do ochrony wewnętrznych sekcji krytycznych systemu

operacyjnego.

Sprzętowa ochrona sekcji krytycznej

DO UZUPEŁNIENIA

TAS - sprawdź i przypisz

CAS - porównaj i zamień

XCHG - zamień

Semafory i ich zastosowanie

Semafor - jest obiektem abstrakcyjnym służącym do kontrolowania dostępu do
ograniczonego zasobu. Semafory są szczególnie przydatne w środowisku gdzie wiele
procesów lub wątków komunikuje się przez wspólną pamięć.

Ochrona sekcji krytycznej

1. Tworzymy semafor za pomocą funkcji sem_init(), której pierwszym parametrem

jest wskaźnik na semafor (zmienna typu semaphore), a drugim początkowa

wartość semafora.

2. Wywołujemy sem_wait(). Funkcja ta dekrementuje wartość semafora jeśli

jest on dodatni, a jeśli jest równy 0 to blokuje proces bieżący, który zostanie
odblokowany wtedy, gdy inny proces wywoła na tym samym semaforze

sem_post()

.

3. Wykonujemy kod sekcji krytycznej
4. Wywołujemy sem_post(), który albo odblokowuje inny proces oczekujący na tym

semaforze, albo inkrementuje wartość semafora.

Generalnie kwestia tej zmiennej, zera itp jest dość prosta, ale trzeba sobie to wyobrazić.

Semafory nienazwane i nazwane POSIX

Wyróżnione są tu dwa typy semaforów:

background image

1. Semafory nienazwane - dostęp do semafora nienazwanego następuje po adresie

semafora. Stąd nazwa semafor nienazwany.

2. Semafory nazwane - identyfikowane są w procesach poprzez ich nazwę. Na

semaforze nazwanym operuje się tak samo jak na semaforze nienazwanym z
wyjątkiem funkcji otwarcia i zamknięcia semafora.


Semafory nienazwane nadają się do synchronizacji wątków w obrębie jednego procesu.
Dostęp do semafora nienazwanego następuje poprzez jego adres. Może on być także
użyty do synchronizacji procesów o ile jest umieszczony w pamięci dzielonej. Dostęp do
semaforów nazwanych następuje poprzez nazwę. Ten typ semaforów bardziej nadaje się
synchronizacji procesów niż wątków. Semafory nienazwane działają szybciej niż nazwane.

Funkcje

sem_open

sem_init

sem_wait

sem_post

Monitory

Definicja

Monitor jest strukturalnym narzędziem synchronizacji.

Zmienne i procedury, które na nich operują są zebrane w jednym module. Dostęp
do zmiennych monitora jest możliwy tylko i wyłącznie za pomocą procedur
monitora.

Tylko jeden proces może w danej chwili wywoływać procedury monitora. Każdy
inny proces chcący wywołać procedurę monitora zostanie zablokowany, aż pierwszy
proces nie skończy.

Można wstrzymywać i wznawiać procedury monitora za pomocą zmiennych
warunkowych, na których można wykonywać operacje wait() i signal().

Zastosowanie

DO ZROBIENIA

Oczekiwanie wewnątrz monitora

Podejrzewam, że chodzi o wait().
Mianowicie, w trakcie wykonywania procedury monitora można wywołać wait(), po czym
obecny proces zostanie wstrzymany i wrzucony na koniec kolejki procesów oczekujących
na mieszanie w monitorze lub jakiejś kolejki uprzywilejowanej (zależy od implementacji),

background image

a dostęp do monitora zostaje przekazany innemu procesowi.
Ma to sens w przypadku, kiedy wykonujemy jakąś operację na monitorze, ale okazuje się,
że musimy czekać na jeszcze coś innego. Wtedy, zamiast blokować inne procesy czekające
na dostęp do monitora i bezczynnie czekać, możemy wpuścić kogoś samemu czekając.

Zmienne warunkowe

DO ZROBIENIA

Funkcje

wait

signal

noempty

notify

broadcast

Implementacja semafora poprzez monitor

DO ZROBIENIA

Wątki

Wątek

– elementarna jednostka szeregowania korzystająca z zasobów procesu.

Wątki wykonywane w ramach jednego procesu dzielą jego przestrzeń adresową i
inne zasoby procesu.
W ramach jednego procesu może się wykonywać wiele wątków

Własności wątków

● Koszt utworzenia i przełączania wątku jest mniejszy niż procesu.
● Dane statyczne procesu są dla wątków działających w ramach jednego

procesu wzajemnie widoczne.

● Wykonanie każdego wątku przebiega sekwencyjnie, każdy wątek ma swój

licznik rozkazów.

● Wątki mogą być wykonywane na oddzielnych procesorach co umożliwia

przyspieszenie obliczeń.

● Ponieważ wątki dzielą wspólne dane konieczna jest synchronizacja dostępu

do tych wspólnych danych.

Wątki pojęcie i zasoby

Wątek dzieli ze swym procesem macierzystym następujące zasoby:

● Dane statyczne (segment danych)

background image

● Deskryptory otwartych plików, blokady plików
● Maskę tworzenia plików (umask)
● Środowisko
● Katalog macierzysty i główny
● Limity zasobów (setrlimit)
● Timery
● Sesję, użytkownika, grupę, terminal sterujący

Zasoby własne wątku:

● Identyfikator wątka (thread ID)
● Maska sygnałów
● Zmienna errno
● Priorytet i strategię szeregowania

Atrybuty i zasoby własne wątku:

1. Identyfikator wątku TID (ang.Thread Identifier) - każdy watek ma unikalny w

ramach procesu identyfikator. Jest to liczba całkowita. Pierwszy wątek ma TID
1, następny 2 itd.

2. Zestaw rejestrów (ang. Register set) - każdy wątek posiada własny obszar

pamięci w którym pamiętany jest zestaw rejestrów procesora (tak zwany
kontekst procesora). Gdy watek jest wywłaszczany lub blokowany w obszarze
tym pamiętane są rejestry procesora. Gdy watek będzie wznowiony obszar
ten jest kopiowany do rejestrów procesora.

3. Stos (ang. Stack) - każdy wątek ma swój własny stos umieszczony w

przestrzeni adresowej zawierającego go procesu. Na stosie tym pamiętane są
zmienne lokalne wątku.

4. Maska sygnałów (ang. Signal mask) - każdy wątek ma swą własną maskę

sygnałów. Maska sygnałów specyfikuje które sygnały mają być obsługiwane
a które blokowane. Początkowa maska jest dziedziczona z procesu
macierzystego.

5. Obszar TLS wątku (ang. Thread Local Storage) – każdy wątek ma

pewien obszar pamięci przeznaczony na utrzymywanie różnych danych
administracyjnych takich jak TID, PID, początek stosu, kod ewentualnego
błędu errno i inne dane. Obszar TLS jest odpowiednikiem deskryptora

procesu.

6. Procedura zakończenia (ang. Cancellation Handler) - gdy wątek się kończy

wykonywana jest procedura zakończenia w ramach której zwalniane są
zasoby wątku.

Tworzenie

Tworzenie wątku
Nowy wątek tworzy się przy pomocy funkcji pthread_create. Funkcja ta tworzy

wątek, którego kod znajduje się w funkcji podanej jako argument func. Wątek jest

uruchamiany z parametrem arg, a informacja o nim jest umieszczana w strukturze

background image

thread

.

Synchronizacja

W bibliotece pthreads do zapewnienia wyłączności dostępu do danych stosuje się
mechanizm muteksu (ang. mutex). Nazwa ta pochodzi od słów Mutual exclusion
czyli
wzajemne wykluczanie.

Funkcje

pthread_create

pthread_join -

Funkcja pthread_join zawiesza działanie wołającego wątku

aż do momentu, gdy watek podany jako argument nie zakończy działania.
-odczytuje wartość zakończenia wątku

pthread_exit

Mutexy

mutex_init

mutex_lock -

Zajęcie muteksu - zapewnia wyłączność w korzystaniu z zasobu.

mutex_unlock -

Zwolnienie muteksu - zwalnia użyty i zablokowany wcześniej

zasób

.

Działanie funkcji mutex_unlock zależy od tego czy inne wątki czekają

zblokowane na muteksie:

1. Brak wątków zablokowanych na muteksie – stan muteksu zostaje

zmieniony na wolny.

2. Są wątki zablokowane na muteksie – jeden z czekających wątków zostaje

odblokowany

Zmienne warunkowe

Zmienna warunkowa jest narzędziem do blokowania wątku wewnątrz sekcji
krytycznej aż do momentu gdy pewien warunek zostanie spełniony. Warunek ten
może być dowolny i niezależny od zmiennej warunkowej. Zmienna warunkowa
musi być użyta w połączeniu z muteksem o ile konstrukcja ma zapewnić własności
monitora

.

cond_init

cond_wait -

Zawieszenie wątku w kolejce.

cond_signal -

Wznowienie wątku zawieszonego w kolejce danej zmiennej

warunkowej.

cond_broadcast -

Wznowienie wszystkich wątków zawieszonych w kolejce

danej zmiennej warunkowej.

background image

Blokady czytelników i pisarzy

Zasada działania blokad czytelników i pisarzy:

● Odczyt może być wykonywany współbieżnie do innych odczytów
● Zapis musi być wykonywany w trybie wyłącznym względem innych zapisów

lub odczytów.

Stan blokady:

● Wolna
● Zajęta do odczytu być może przez wiele wątków czytających
● Zajęta do zapisu

Wirujące blokady

Wirujące blokady są środkiem zabezpieczania sekcji krytycznej. Wykorzystują
jednak czekanie aktywne zamiast przełączenia kontekstu wątku tak jak się to dzieje
w muteksach.
Blokada może być w dwóch stanach:·

● Wolna
● Zajęta

pthread_spin_init - podczas inicjacji wirującej blokady definiujemy czy

mogą

operować wątki należące do różnych procesów czy tylko wątki należące do
tego samego procesu

pthread_spin_lock - Zajęcie blokady -

Działanie funkcji zależy od stanu

blokady. Gdy blokada jest wolna następuje jej zajęcie. Gdy blokada jest
zajęta wątek wykonujący funkcję pthread_spin_lock(...)ulega

zablokowaniu do czasu gdy inny wątek nie zwolni blokady wykonując funkcję

pthread_spin_unlock

pthread_spin_unlock - zwolnienie blokady -

Działanie funkcji zależy od stanu

blokady. Gdy są wątki czekające na zajęcie blokady to jeden z nich zajmie
blokadę. Gdy żaden wątek nie czeka na zajęcie blokady będzie ona
zwolniona.

Inwersja priorytetów

Dzika sytuacja,

gdy dwa lub więcej wątki o różnych priorytetach używają wspólnego

zasobu chronionego przez pewien mechanizm zapewnienia wzajemnego
wykluczania (np. muteks)
Inwersja priorytetów – zjawisko polegające na wykonywaniu się wątku o niższym
priorytecie mimo, iż wątek o wyższym priorytecie pozostaje gotowy. Inwersja
priorytetów może się pojawić gdy wątki o różnych priorytetach używają wspólnego
muteksu lub podobnego mechanizmu synchronizacyjnego.

background image

Ochrona przed inwersją

W systemach czasu rzeczywistego stosowane są dwie strategie postępowania z
problemem inwersji priorytetów. Jest to:
1. Dziedziczenie priorytetu (ang.Priority Inheritance)
2. Zastosowanie stosowanie protokołu wykorzystującego tzw. pułap priorytetów
(ang.
Priorty Ceiling)

Metody dziedziczenia priorytetów

Dziedziczeniem priorytetu polega na tym, że gdy wątek W3 o wyższym priorytecie
próbuje zająć muteks zajęty już przez wątek W1 o priorytecie niższym, to system
podwyższa chwilowo priorytet wątku W1 zajmującego muteks do wysokości
priorytetu wątku W3. Dzięki podwyższonemu priorytetowi wątek W1 szybciej wykona
swe zadanie i zwolni muteks. Po zwolnieniu muteksu wątkowi W1 zostaje mu
przywrócony pierwotny priorytet.

I piękna definicja
Dziedziczeniem priorytetu – tymczasowe zwiększenie priorytetu wątku
posiadającego zasób do najwyższego priorytetu z priorytetów wątków ubiegających
się o zajęcie tego zasobu. Po zwolnieniu zasobu wątkowi przywracany jest
początkowy priorytet.

Dodatkowa wiedza
Protokół dziedziczenia priorytetów działa prawidłowo w przypadku użycia jednego
typu zasobu. Gdy używana jest większa liczba zasobów może dojść do różnych
niekorzystnych zjawisk jak:

● blokowanie przechodnie
● zakleszczenie.

Metody pułapu priorytetów

Każdemu chronionemu zasobowi (w tym przypadku jest to muteks) przypisuje
się pewien określony statyczny priorytet. Priorytet ten powinien być wyższy od
najwyższego priorytetu z tych wątków które o dany zasób będą konkurowały. Gdy
jakiś wątek będzie próbował zająć zasób to zostanie mu tymczasowo przydzielony
priorytet związany z tym
zasobem. Po zwolnieniu zasobu priorytet wątku wróci do wielkości wyjściowej.

Protokół z pułapem priorytetu
(ang. priority ceiling protocol)
W protokole z pułapem priorytetu następuje tymczasowe zwiększenie priorytetu w
wątku usiłującego zająć zasób do pewnego ustalonego priorytetu (wyższego

background image

od priorytetu jakiegokolwiek wątku konkurującego o zasób). Wszystkim wątkom
konkurujące o zasób zostaje tymczasowo nadany ten jednakowy priorytet. Dzięki
temu że watek zajmujący zasób zyskuje chwilowo priorytet wyższy niż jakiekolwiek
inny wątek konkurujący o zasób – ma on szansę zakończyć operację na zasobie bez
wywłaszczenia.

Zalety protokołu:

● Protokół zapobiega powstawaniu zakleszczeń.
● Zapewnia dobry czas oczekiwania na zasób (dla najgorszego przypadku)

poprzez wątek o najwyższym priorytecie. Czas ten równy jest długości
najdłuższej sekcji krytycznej wątków o niższym priorytecie.


Wady protokołu:

● Należy z góry wyznaczyć zbiór wszystkich wątków które będą konkurowa ły o

zasób i jako pułap priorytetu przyjąć najwyższy priorytet z zadań z tego zbioru
+ 1 . Może to być czasochłonne lub nawet niemożliwe.

● Posiada zły średni czas odpowiedzi z związku z narzutami na implementację.

Gniazdka

Interfejs gniazd

Jednolity interfejs API (Application Program Interface) do mechanizmów
komunikacji sieciowej.
Główna idea gniazdek polega na użyciu do komunikacji (lokalnej i zdalnej)
tego samego mechanizmu, co dostępu do plików. Jest to mechanizm oparty o
deskryptory plików i funkcje read, write .


Termin gniazdko ma dwa znaczenia:

1. Biblioteka + funkcje interfejsowe (API).
2. Końcowy punkt komunikacji

Biblioteka gniazdek maskuje mechanizmy transportu sieci.

Własności gniazd:

● Gniazdo jest identyfikowane przez liczbę całkowitą nazywaną deskryptorem

gniazda

● Gniazdo można nazwać i wykorzystywać do komunikacji z innymi gniazdami

w tej samej domenie komunikacyjnej

Komunikacja bezpołączeniowa - Komunikacja bez

background image

kontroli połączenia

Klient:
Tworzy gniazdko

- socket

Nadaje gniazdku adres

- bind (konieczne przy odbiorze)

Nadaje lub odbiera dane

- sendto, recfrom, write, read, recv, send

Serwer:
Tworzy gniazdko

- socket

Nadaje gniazdku adres

- bind (konieczne przy odbiorze)

Nadaje lub odbiera dane

- sendto, recfrom, write, read, recv, send

Funkcja recfrom

- Odbiór danych z gniazdka - umożliwia odczyt bajtów z

gniazdka znajdującego sięw stanie niepołączonym jak i połączonym.

Funkcja sendto

- Zapis do gniazdka - Funkcja sendto umożliwia wysłanie

bajtów do gniazdka znajdującego się w stanie nie połączonym jak i połączonym.

Komunikacja połaczeniowa - Transmisja z kontrolą
połączenia

Klient:
1. Tworzy gniazdko

socket

2. Nadaje gniazdku adres

bind

(konieczne przy odbiorze)

3.Łączy się z serwerem

connect

4. Nadaje lub odbiera dane

write, read, recv, send


Serwer:
1. Tworzy gniazdko

socket

2. Nadaje gniazdku adres

bind

(konieczne przy odbiorze)

3. Wchodzi w tryb akceptacji po łączeń listen

4. Oczekuje na po łączenia

accept


Gdy połączenie zostanie nawiązane:

1. Tworzy dla tego po łączenia nowe gniazdko
2. Nadaje lub odbiera dane - write, read, recv, send

3. Zamyka gniazdko

Funkcje

connect - Połączenie ze zdalnym gniazdkiem. Funkcja powoduje próbę nawiązania
połączenie ze zdalnym gniazdkiem wyspecyfikowanym jako adres.

listen - Wprowadzenie serwera w stan gotowości do nawiązania połączenia

accept - Nawiązanie połączenia przez serwer -

background image

Działanie funkcji accept:

Wywołanie accept może być blokujące. Gdy przychodzi nowe połączenie

następuje odblokowanie procesu bieżącego i wykonanie następujących czynności:

1. Pobranie pierwszego połączenie z kolejki oczekujących połączeń.
2. Utworzenie nowego gniazdka o identycznych własnościach jak gniazdko

utworzone poleceniem socket.

3. Alokacja nowego deskryptora pliku dla gniazdka.
4. Nadanie wartości parametrom name i namelen.

read - Odczyt z gniazdka – Funkcja jest używana do odbioru danych z gniazdka
w trybie połączeniowym. Funkcja powoduje odczyt z gniazdka i umieszczenie
odczytanych n bajtów w buforze.

write - j.w tylko w 2 strone

recv

-

Funkcja jest używana do odbioru danych z gniazdka w trybie

połączeniowym lub bezpołączeniowym. - podobnie jak read, ale występuje
tu dodatkowy 3 parametr z flagami: MSG_WAITALL - Funkcja czeka na

tyle bajtów ile wymieniono w wywołaniu, MSG_OOB - Odbiór danych poza

pasmem – znaczenie zależy od protokołu, MSG_PEEK Dane odczytane na

próbę, nie znikają z bufora

send - analogicznie

Serwer sekwencyjny

Serwer sekwencyjny to serwer składający się z jednego tylko procesu. W danej chwili
może on obsługiwać tylko jednego klienta.
Klient:

1. Lokalizacja serwera
2. Utworzenie komunikatu specyfikującego żądanie
3. Wysłanie komunikatu do procesu serwera
4. Odbiór odpowiedzi.
5. Wykorzystanie wyniku.

Serwer:

1. Rejestracja nazwy własnej w serwerze nazw.
2. Odbiór zlecenia.
3. Identyfikacja zlecenia
4. Realizacja zlecenia.
5. Wysłanie odpowiedzi do klienta

Serwer współbieżny

Współbieżne działanie serwera pozwala, w sytuacji gdy do serwera łączy się wielu
klientów, na ich współbieżne obsłużenie.

Schemat działania serwera współbieżnego

background image

1.

Tworzy gniazdko

- socket

2.

Nadaje gniazdku adres

- bind (konieczne przy odbiorze)

3.

Wchodzi w tryb akceptacji połączeń - listen

4.

Oczekuje na połączenia

- accept

5.

Gdy przychodzi nowe połączenie funkcja accept zwraca identyfikator

nowego gniazdka. To gniazdko będzie używane w połączeniu z klientem. Dla
połączenia tworzy się nowy proces i przechodzi się do 4.


Proces obsługujący połączenie:
Korzysta z nowego gniazdka którego numer jest przekazany jako parametr

1. Nadaje lub odbiera dane

- write, read, recv, send

2. Zamyka gniazdko

Sygnały

Sygnały i ich obsługa

Sygnał – mechanizm asynchronicznego powiadamiania procesów o zdarzeniach –
zwykle awaryjnych.

Sygnały mogą być generowane przez:

1. System operacyjny, zwykle po wykonaniu nieprawidłowej operacji.
2. Z konsoli operatorskiej poprzez polecenia kill i slay.
3. Z programu aplikacyjnego poprzez funkcje (np. kill, raise, abort, alarm, i inne)

oraz timery.


Proces może zareagować na sygnały w sposób następujący:

1. Obsłużyć sygnał czyli wykonać funkcję dostarczoną poprzez programistę.
2. Zignorować sygnał – nie każdy sygnał daje się zignorować.
3. Zablokować sygnał to znaczy odłożyć jego obsługę na później.
4. Zakończyć się po otrzymaniu sygnału.


Reakcja procesu na sygnał w zależności od stanu w jakim znajduje się proces.

1. Gdy proces jest wykonywany lub gotowy to następuje przerwanie sekwencji

wykonania i skok do procedury obsługi sygnału.

2. Gdy proces jest zablokowany to następuje jego odblokowanie i wykonanie

procedury obsługi tego sygnału.

Instalacja handlera sygnału

Funkcje:

background image

signal() (UNIX)
void(*signal(int sig, void(*func)(int)))(int))
gdzie sig to numer lub symbol sygnału, a func jest wskaźnikiem na funkcję
która ma być wykonana. Nie można obsłużyć sygnałów SIGSTOP i SIGKILL.
Jako funkcję można podać SIG_IGN (ignore) lub SIG_DFL- domyślna reakcja
na sygnał (zakończenie lub zignorowanie)

sigaction() (POSIX)
int sigaction(int signo, struct sigaction *act, struct sigaction *oldact),

sigaction to struktura z informacjami o obsłudze sygnału:
struct sigaction {

void (*sa_handler)(int) ;
void(*sa_sigaction)(int signo,siginfo_t *info, void *inne)
sigset_t sa_mask; // Sygnały blok. podczas obsługi
int sa_flags; // Flagi modyfikacji działania

}

Dokładny opis parametrów: 13_Sygnaly.pdf strona 15

Blokowanie sygnałów

Blokada sygnałów
Podczas obsługi sygnału dostarczanie innych sygnałów jest zablokowane.
2. Sygnały i funkcje systemowe
W większości przypadków w czasie wykonania funkcji systemowych sygnały są
zablokowane. Wyjątek stanowią:
- Funkcje read, write, open w odniesieniu do terminali.

- Funkcje wait, pause, sigsuspend

Funkcje te będą przerywane przez sygnał. Możliwe jest ustawienie flagi
SA_RESTART aby przerwane funkcje kontynuować.

Sygnały a wątki

Sygnały mogą być kierowane do procesów i do wątków.

Zachowanie się sygnałów w środowisku procesów wielowątkowych zdefiniowane
jest regułami:
1. Sygnały obsługiwane są na poziomie procesu. Znaczy to że gdy wątek zignoruje
lub obsłuży sygnał, fakt ten wpływa na inne wątki tego procesu.
2. Maskowanie sygnałów zachodzi na poziomie wątków.
3. Jeżeli sygnał skierowany jest do określonego wątku to będzie on do tego wątku
dostarczony.
4. Jeżeli sygnał skierowany jest do procesu to będzie dostarczony do pierwszego
wątku który nie blokuje danego sygnału.

Zasada obsługi sygnałów w środowiskach wielowątkowych:

background image

Standardową strategią obsługi sygnałów w środowisku procesów wielowątkowych
jest zamaskowanie sygnałów we wszystkich watkach z wyjątkiem jednego. Ten
właśnie wątek będzie obsługiwał sygnały.

Timery

Timery - specjalne obiekty systemu operacyjnego, odpowiedzialne za generowanie
zdarzeń które w ustalonym czasie uruchomić mają określone akcje systemu.

Timery mogą wywoływać sygnał lub tworzyć nowy wątek, w zalezności o tego, co
wybierzemy w strukturze sigevent przekazywanej jako argument do funkcji tworzącej
nowy timer.

Posługiwanie się timerem

1. Tworzymy strukturę typu sigevent, w której wybieramy, co timer ma zrobić po

odliczeniu czasu (nowy wątek, sygnał itp),

2. Tworzymy timer za pomocą timer_create()
3. Wybieramy sposób określenia czasu - absolutny lub relatywny (parametr funkcji

timer_settime())

4. Wybrać tryb pracy - jednorazowy lub cykliczny

W strukturze itimerspec mamy dwa pola - value, czyli czas, który musi upłynąć
przed pierwszą aktywacją timera, i interval, czyli czas pomiędzy kolejnymi
wywołaniami timera. Można ustawić interval na 0, co będzie skutkować
jednorazową aktywacją timera.

5. Nastawić timer, czyli wywołaś timer_settime() z odpowiednimi parametrami.

RPC

Zdalne wykonywanie procedur RPC

DO ZROBIENIA

Podstawowe pojęcia

Przetaczanie parametrów (ang. parameters marschalling) – pakowanie parametrów
procedury do komunikatu z jednoczesną konwersją danych.
Przetaczanie parametrów obejmuje:
1. Konwersję formatu komunikatu
2. Serializację danych

background image

Namiastka klienta (ang. client stub) - reprezentuje serwer po stronie klienta
Namiastka serwera (ang. server stub) - reprezentuje klienta po stronie serwera

Synchroniczne RPC - klient czeka na odpowiedź serwera
Asynchroniczne RPC - klient przekazuje parametry do serwera i kontynuuje działanie.
Odroczone asynchroniczne RPC - klient przekazuje parametry do serwera i kontynuuje
działanie. Gdy serwer opracuje odpowiedź wywołuje procedurę po stronie klienta.

Wiązanie dynamiczne

Przy zdalnym wywoływaniu procedur powstaje pytanie jak klient ma zlokalizować procedury
serwera.

Wiązanie (ang. binding) – odwzorowanie nazwy (procedury RPC) w konkretny obiekt
określony identyfikatorem komunikacyjnym. Postać identyfikatora zależy od systemu (np.
adres gniazdka - IP, port).
Łącznik (ang. binder) – specjalna usługa RPC utrzymująca tablicę odwzorowań nazw usług
(procedur RPC) na porty serwerów tych usług. Łącznik utrzymywany jest przez serwery
które udostępniają identyfikatory portów swoim klientom. Od usług łącznika zależą wszystkie
inne usługi. Dlatego łączniki tworzy się tak aby tolerowały awarie. Np. tablice odwzorowań
zapisuje się w pliku z którego mogą być one wczytane w przypadku awarii.

Język opisu interfejsu IDL

DO ZROBIENIA

Tworzenie aplikacji w standardzie Sun RPC

Realizacja Sun RPC oparta jest na gniazdkach. Mechanizm gniazdek
jest zamaskowany przed użytkownikiem. Ma on do dyspozycji funkcje
wyższego poziomu.
Można korzystać z protokołu:
· TCP
· UDP (rozmiar danych ograniczony do 8 KB).

Dostępne trzy poziomy:
Poziom pierwszy - gotowych funkcji (np. nusers - liczba zal. użytk.)
Poziom pośredni – łatwy w użyciu lecz ograniczona funkcjonalność
Poziom trzeci – stosowane są funkcje niskiego poziomu, pełna funkcjonalność
Najczęściej stosowany jest poziom pośredni. Jest on odpowiedni dla
większości typowych aplikacji.

Aplikacja poziomu pośredniego nie umożliwia:
· Kontroli przeterminowań
· Użycie wielu procesów / wątków po stronie serwera
· Elastycznej obsługi błędów
· Użycia zaawansowanej identyfikacji strony wywołującej

background image


Tworzenie aplikacji RPC odbywa się w następujących krokach:

1. Utworzenie interfejsu serwera – specyfikacja (w języku opisu interfejsu RPCGEN )

co serwer ma wykonać i jak przekazuje się parametry.

2. Przy użyciu programu rpcgen

generuje się namiastkę klienta (ang. client stub),

namiastkę serwera (ang. server stub), plik nagłówkowy, plik konwersji.

3. Implementacja usług serwerowych.
4. Implementacja aplikacji klienta – wykorzystanie stopki klienta.

Program serwera działa według schematu:
1. Otrzymanie identyfikatora transportu (ang. transport handle)
2. Zarejestrowanie usługi u demona portmap
3. Oczekiwanie na zgłoszenia klienta i wykonywanie jego zleceń

Program klienta działa według schematu:
1. Otrzymanie identyfikatora klienta (ang. client handle)
2. Wywoływanie odległych procedur
3. Likwidacja identyfikatora klienta gdy nie jest potrzebny

Linda

System Linda

System Linda jest oryginalnym i zarazem mocną koncepcją tworzenia systemów
współbieżnych i równoległych. Linda nie jest samodzielnym językiem programowania ale
dodatkiem do innych języków. A więc istnieje C-Linda, FORTRAN-Linda i inne. Koncepcyjnie
Linda jest prosta a fakt że stanowi ona dodatek do znanego już języka (nie trzeba się uczyć
od początku) podnosi jej atrakcyjność. Linda bazuje na koncepcji pamięci dzielonej (być
może rozproszonej) nazywanej przestrzenią krotek TS (ang. Tuple Space) i niewielkiej
liczbie operacji zapewniającej dostęp do tej przestrzeni, synchronizację i wzajemną
komunikację procesów współbieżnych. Koncepcja Lindy wspiera model programowania
równoległego znany jako zarządca – wykonawca (ang. Worker – Manager). Koncepcja
systemu pochodzi od Davida Gelerntera z Yale University. Linda jest językiem opisującym
koordynację (ang. cordination language) (synchronizację i komunikację) procesów.

Linda – własności

● Wspiera tworzenie aplikacji równoległych typu zarządca – wykonawca
● Kod niezależny od liczby procesów wykonawczych
● Wspiera równoległość i komunikację międzyprocesową
● Nakładanie się komunikacji i obliczeń
● Nadaje się do systemów heterogenicznych (składających się z różnych maszyn)

Przestrzeń krotek

background image

Przestrzeń krotek TS jest abstrakcją zawierającą posiadające typy ciągi danych. Przestrzeń
krotek jest globalna w całym systemie chociaż może być implementowana na maszynach z
rozproszoną pamięcią dzieloną.

Przestrzeń krotek – dzielona przestrzeń danych.
Krotka – lista do 16 pól zawierających dane języka bazowego. Pola te są rozdzielone
przecinkami. W języku C-Linda pola mogą być znakami, łańcuchami, typu całkowitego,
rzeczywistego lub typami złożonymi jak tablice lub struktury ale nie zawierające krotek.

Przykłady krotek:
(“dane1”, 13, 2)
(x1, x2)
(“zadanie1”,i,j)

Przestrzeń krotek oparta jest na pamięci asocjacyjnej.
· Dostęp do krotek opiera się na ich zawartości
· Krotki nie posiadają adresu przez który można by do nich sięgnąć.

Krotki mogą zawierać dwie kategorie danych:
· Parametry rzeczywiste (ang. actual parameters) – zawierają ustalone dane pewnego typu.
· Parametry formalne (ang. formal parameters) – są pojemnikiem na dane pewnego typu.

Krotki dziurawe
Krotki zawierające parametr formalny nazywane są krotkami dziurawymi.
Znak ? oznacza że jest to parametr formalny. Ma on typ ale nie posiada wartości.
Przykład:
("rzeczywisty", ",formalny",? x) – x jest zmienną typu int

Krotki pasywne i aktywne.
· Krotki mogą być pasywne lub aktywne.
· Krotka pasywna zawiera ustalone dane.
· Krotka aktywna zawiera przynajmniej jeden parametr którego wartość nie jest jeszcze
ustalona. Taki nieustalony parametr jest funkcją. Gdy krotka aktywna umieszczana jest w
przestrzeni krotek system tworzy współbieżny proces który oblicza jej wartość.
· Po obliczeniu wartości wynik jest wstawiany do krotki i krotka staje się pasywna.

Przykład:
("test", i, f(i));

Operacje

out

Umieszczenie krotki pasywnej w TS

eval

Umieszczenie krotki aktywnej w TS

in

Pobranie krotki z TS – wersja blokująca

inp

Pobranie krotki z TS – wersja nieblokująca

rd

Odczyt krotki z TS – wersja blokująca

background image

rdp

Odczyt krotki z TS – wersja nieblokująca

Wyrażanie operacji synchronizacyjnych i
komunikacyjnych

DO ZROBIENIA

Problem producenta i konsumenta,
czytelników i pisarzy

Rozwiązanie za pomocą semaforów

DO ZROBIENIA

Rozwiązanie za pomocą monitorów

DO ZROBIENIA

Rozwiązanie za pomocą zmiennych warunkowych

DO ZROBIENIA

Rozwiązanie za pomocą mechanizmów języka Linda

DO ZROBIENIA


Wyszukiwarka

Podobne podstrony:
AK opracowanie zagadnien na egzamin 2011
Opracowanie Zagadnień na egzamin Mikroprocki
monopolizacja gospodarki, Opracowane zagadnienia
Opracowanie zagadnień NIK, Bezpieczenstwo Narodowe rok I
temp krytyczna, TRANSPORT PWR, STUDIA, SEMESTR II, FIZYKA, fizyka-wyklad, zagadnienia opracowane, za
socjologia - opracowane zagadnienia(2), Uniwerek
Opracowane zagadnienia na koło z podstaw turystyki, Notatki na koła
opracowane zagadnienia ściąga nowa
chemia fizyczna wykłady, sprawozdania, opracowane zagadnienia do egzaminu Sprawozdanie ćw 7 zależ
Drobnoustroje chorobotwórcze opracowane zagadnienia
Egzamin opracowane zagadnienia 2
Opracowanie zagadnień na prawo handlowe
Podstawy biologicznego rozwoju człowieka opracowane zagadnienia z roku 14 2015
opracowane zagadnienia na egazamin
Opracowane Zagadnienia
Socjologia organizacji socjologia organizacji opracowanie zagadnien

więcej podobnych podstron