Laboratorium Podstawy Przetwarzania Rozproszonego SPRAWOZDANIE z zadania SERWIS KOMPUTEROWY Nazwisko Imię album termin zajęć Marek Lewandowski 59817 Maciej Mietliński 59832 poniedziałek 18:30 tydzień nieparzysty Część I Algorytm rozwiązania 1. Definicja problemu System złożony z K komputerów, które niestety systematycznie wymagają serwisowania. Serwis posiada N stanowisk naprawczych umożliwiających jednoczesną naprawę do N maszyn. Przed naprawą każdy komputer musi być przyjęty na dowolnym spośród dostępnych S stanowisk przyjęć, a po naprawie wydawany jest również przez jedno dowolne z nich. Przyjmujemy: K > N > S. Napisać program dla procesu komputera umożliwiający mu systematyczne serwisowanie wg powyższych zasad. Stanowiska przyjęć/wydań oraz naprawcze należy traktować jako zasoby. 2. Założenia przyjętego modelu komunikacji asynchroniczny system z wymianą komunikatów topologia połączeń: każdy z każdym wymagana pojemność kanału: zakładamy, że jednocześnie może być wysyłana ( w jedną stronę) tylko jedna wiadomość. inne wymagane własności sieci komunikacyjnej: kanały typu FIFO, transmisja rozgłoszeniowa. 3. Algorytm wzajemnego wykluczania Do rozwiązania problemu serwisu komputerowego zaproponowaliśmy algorytm Lamporta. o gdy P i decyduje o podjęciu próby wejścia do sekcji krytycznej zapamiętuje aktualną wartość swojego zegara skalarnego T i Kolejność ubiegania się o poszczególne sekcje krytyczne: o o o o P i ubiega się o dostęp do stanowiska naprawy (N) P i ubiega się o dostęp do stanowiska przyjęć (S) naprawa P i ubiega się o dostęp do stanowiska przyjęć (S) Proces P i może wejść do sekcji krytycznej, jeśli znajduje się wśród pierwszych N (w przypadku zasobu stanowiska naprawy) lub pierwszych S (w przypadku zasobu stanowiska przyjęć / wydań) początkowych procesów lokalnej kolejki; oraz żaden ze starszych od P i procesów nie ubiega się o dostęp do sekcji krytycznej. Po wyjściu z sekcji krytycznej proces usuwa swoje żądanie z lokalnej kolejki oraz wysyła do pozostałych procesów komunikat zm_zwolnienie_n (lub S). 1/12
PSEUDOKOD: queue KolejkaN, KolejkaS int Potwierdzenia[K] int LicznikPotwierdzen = 0 int Clock = 0 message Msg int PRZYDZIAL_N //żądanie przydziału do stanowiska naprawczego for (i = 0; i < K; i++) Potwierdzenia[i] = false Msg.Type = ZADANIE_N Msg.Clock = Clock + 1 LicznikPotwierdzen = K - 1 Broadcast(Msg) KolejkaN.add(current, Clock) repeat until (LicznikPotwierdzen == 0 && KolejkaN.exist(N, current) return 1 int PRZYDZIAL_S //żądanie przydziału do stanowiska przyjęć for (i = 0; i < K; i++) Potwierdzenia[i] = false Msg.Type = ZADANIE_S Msg.Clock = Clock + 1 LicznikPotwierdzen = K - 1 Broadcast(Msg) KolejkaS.add(current, Clock) repeat until (LicznikPotwierdzen == 0 && KolejkaS.exist(S, current) return 1 int ZWOLNIENIE_S //żądanie przydziału do stanowiska przyjęć for (i = 0; i < K; i++) Potwierdzenia[i] = false Msg.Type = ZWOLNIENIE_S Msg.Clock = Clock + 1 LicznikPotwierdzen = K - 1 Broadcast(Msg) KolejkaS.del(current) return 1 int ZWOLNIENIE_K 2/12
//żądanie przydziału do stanowiska naprawczego for (i = 0; i < K; i++) Potwierdzenia[i] = false Msg.Type = ZWOLNIENIE_K Msg.Clock = Clock + 1 LicznikPotwierdzen = K - 1 Broadcast(Msg) KolejkaN.del(current) return 1 RECEIVE (current, Msg) Clock = max(clock, Msg.clock) + 1 if (Msg.type == PRZYDZIAL_N) KolejkaN.add(current, Msg.clock) Msq.clock = Clock Msg.type = PRZYDZIALN_POTW send(current, Msg) endif if (Msg.type == ZWOLNIENIE_N) delete(kolejkan, current, Msg.clock) endif if (Msg.type == PRZYDZIAL_S) KolejkaS.add(current, Msg.clock) Msq.clock = Clock Msg.type = PRZYDZIALS_POTW send(current, Msg) endif if (Msg.type == ZWOLNIENIE_S) endif delete(kolejkas, current, Msg.clock) if (Msg.type == PRZYDZIALS_POTW Msg.type == PRZYDZIALN_POTW) if (ackflags[current] == false) ackflags[x] = true LicznikPotwierdzen-- endif endif int MAIN 3/12
while (1) ZADANIE_N; ZADANIE_S; ZWOLNIENIE_S; //Sekcja krytyczna ZADANIE_S; ZWOLNIENIE_S; ZWOLNIENIE_N; Endwhile 4. Analiza złożoności komunikacyjnej algorytmu złożoność komunikacyjna pakietowa, wyrażona w liczbie komunikatów: Podczas wykonania jednej pętli głównej programu proces przechodzi trzy razy przez sekcje krytyczne (punkt przyjęcia + naprawa + punkt wydania). Wejście do każdej z sekcji poprzedzone jest następującą sekwencją instrukcji: Broadcast (ŻĄDANIE_PRZYDZIAŁU) (N - 1) wiadomości 1 Receive (POTWIERDZENIE) (N 1) wiadomości Broadcast (zm_zwolnienie) (N 1) wiadomości Zatem na każdą sekcję krytyczną przypada złożoność 3(N 1). Ponieważ, podczas wykonania jednej pełnej pętli programu głównego występują trzy sekcje krytyczne, zatem algorytm posiada złożoność pakietową 9(N 1). złożoność czasowa przy założeniu jednostkowego czasu przesłania pojedynczego komunikatu w kanale: Ponieważ nic nie stoi na przeszkodzie, aby wszystkie wiadomości z poszczególnych grup (Broadcast (ŻĄDANIE_PRZYDZIAŁU), Receive (POTWIERDZENIE), Broadcast (zm_zwolnienie) ), wysyłane były jednocześnie, zatem na każdą sekcję krytyczną przypada złożoność czasowa 3. Ponieważ, podczas wykonania jednej pełnej pętli programu głównego występują trzy sekcje krytyczne, zatem algorytm posiada złożoność czasową 9. Część II Implementacja rozwiązania /* queue.h */ #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <pvm3.h> #define K 5 #define N 3 #define S 2 #define false 0 1 W rzeczywistości wysyłanych jest N wiadomości (wiadomość jest wysyłana do wszystkich członków grupy, w tym do nadawcy), jednakowoż funkcja RECEIVE została tak zaimplementowana, aby przerywać swoje działanie zaraz po wykryciu sytuacji, w której odbiorca jest tożsamy z nadawcą. 4/12
#define true 1 extern int licznik_n; extern int licznik_s; /* wazne! N musi byc rozne niz S! Zmienne licznik przechowuja informacje o tym, ile elementow jest aktualnie w danej tabeli */ struct queue int id; int clock; ; extern struct queue n[k+1]; extern struct queue s[k+1]; extern struct queue KolejkaN[K+1]; extern struct queue KolejkaS[K+1]; extern struct queue element; /* +1 dla bezpieczeństwa */ void init(); /* i - id szukanego *q - wskaznik na kolejke w ktorej ma szukac max - rozmiar tablicy jesli istnieje, zwraca jego id, a jesli nie, to -1 */ int exist_id(int i, struct queue *q, int maxi); int exist_clock(int cl, struct queue *q, int maxi); /* funkcja do porownywania uzywana w quicksort */ int compare(const void* a1, const void* b1); /* do tablicy struktur dodaje strukture. licznik oznacza licznik_n lub licznik_s w zaleznosci od kolejki. max to maksymalny element tablicy - przydatny do rozrozniania s od n */ void add (struct queue *q, struct queue element, int licznik, int maxi); void del (struct queue *q, struct queue element, int licznik, int maxi); int max (int a1, int a2); /* queue.c */ #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <pvm3.h> #define K 5 #define N 3 #define S 2 5/12
#define ZADANIE_N 1 #define ZADANIE_S 2 #define zm_zwolnienie_n 3 #define zm_zwolnienie_s 4 #define PRZYDZIALN_POTW 13 #define PRZYDZIALS_POTW 14 #define false 0 #define true 1 int licznik_n=0; int licznik_s=0; struct queue int id; int clock; KolejkaN[K+1], KolejkaS[K+1], element; void init() printf("init %d \n", pvm_mytid()); for (i=0; i<n; i++) KolejkaN[i].id=INT_MAX; KolejkaN[i].clock=INT_MAX; for (i=0; i<s; i++) KolejkaS[i].id=INT_MAX; KolejkaS[i].clock=INT_MAX; int exist_id(int i, struct queue *q, int maxi) int iter; for (iter=0; iter<maxi; iter++) if ( q[iter].id == i) return q[iter].id; return -1; int exist_clock(int cl, struct queue *q, int maxi) int iter; for (iter=0; iter<maxi; iter++) if ( q[iter].clock == cl) return q[iter].clock; return -1; 6/12
int compare(const void* a1, const void* b1) struct queue a = *(struct queue*)a1; struct queue b = *(struct queue*)b1; if (a.clock < b.clock) return -1; else if (a.clock > b.clock) else if (a.id < b.id) return -1; else void add (struct queue *q, struct queue element, int licznik, int maxi) int tmp = licznik + 1; for (i=0; i<licznik; i++) if (q[i].id == element.id) return; q[licznik]=element; if (maxi==n) ++licznik_n; else ++licznik_s; licznik++; qsort (q, licznik, sizeof(struct queue), compare); void del (struct queue *q, struct queue element, int licznik, int maxi) int iter; int tmp = licznik-1; for (iter=0; iter < licznik; iter++) if ( q[iter].id == element.id ) q[iter].id=int_max; q[iter].clock=int_max; break; qsort (q, licznik, sizeof(struct queue), compare); 7/12
if (maxi==n) licznik_n--; else licznik_s--; int max (int a1, int a2) if(a1>=a2) return a1; else return a2; /* komp_task.c */ #include "queue.h" #include <time.h> #define ZADANIE_N 1 #define ZADANIE_S 2 #define zm_zwolnienie_n 3 #define zm_zwolnienie_s 4 #define PRZYDZIALN_POTW 13 #define PRZYDZIALS_POTW 14 int Potwierdzenia[K] = 0; int LicznikPotwierdzen = 0; int Clock = 0; int numer = -1; int PRZYDZIAL_N( void ); int PRZYDZIAL_S( void ); int ZWOLNIENIE_N( void ); int ZWOLNIENIE_S(void); void uruchom(); void serwis(); int receive(); void send(int, int, int); //int Msg[4]; /*[0]-typ, [1]-clock, [2]-nadawca, [3]-numer klienta*/ int receive() int Msg[4]=0; int tmp = pvm_nrecv( -1, -1 ); if (tmp == 0 ) return -1; pvm_upkint(msg, 4, 1); if (Msg[2] == pvm_mytid()) return -1; 8/12
Clock = max(clock, Msg[1]) + 1; element.id = Msg[2]; element.clock = Msg[1]; if (Msg[0] == ZADANIE_N) Msg[0] = PRZYDZIALN_POTW; add(kolejkan, element, licznik_n, N); send(clock, Msg[2], Msg[0]); if (Msg[0] == zm_zwolnienie_n) del(kolejkan, element, licznik_n, N); if (Msg[0] == ZADANIE_S) Msg[0] = PRZYDZIALS_POTW; add(kolejkas, element, licznik_s, S); send(clock, Msg[2], Msg[0]); if (Msg[0] == zm_zwolnienie_s) del(kolejkas, element, licznik_s, S); if (Msg[0] == PRZYDZIALS_POTW Msg[0] == PRZYDZIALN_POTW) if (Potwierdzenia[Msg[3]] == 0) Potwierdzenia[Msg[3]] = 1; LicznikPotwierdzen--; int PRZYDZIAL_N() int Msg[4]=0; for (i = 0; i < K; i++) Potwierdzenia[i] = 0; ++Clock; Msg[0] = ZADANIE_N; Msg[2] = pvm_mytid(); Msg[3] = numer; LicznikPotwierdzen = K - 1; pvm_initsend(pvmdataraw); pvm_pkint(msg, 4, 1); 9/12
pvm_bcast("slave", ZADANIE_N); element.id = pvm_mytid(); element.clock = Clock; add(kolejkan, element, licznik_n, N); while (1) receive(); if ( LicznikPotwierdzen == 0 && exist_id ( pvm_mytid(), KolejkaN, N ) >=0 ) break; sleep(1); int PRZYDZIAL_S() int Msg[4]=0; ++Clock; for (i = 0; i < K; i++) Potwierdzenia[i] = 0; Msg[0] = ZADANIE_S; Msg[2] = pvm_mytid(); Msg[3] = numer; LicznikPotwierdzen = K - 1; pvm_initsend(pvmdataraw); pvm_pkint(msg,4,1); pvm_bcast("slave", ZADANIE_S); element.id = pvm_mytid(); element.clock = Clock; add(kolejkas, element, licznik_s, S); while (1) receive(); if ( LicznikPotwierdzen == 0 && exist_id ( pvm_mytid (), KolejkaS, S) >= 0 ) break; sleep(1); int ZWOLNIENIE_S() int Msg[4]=0; element.id = pvm_mytid(); ++Clock; Msg[0] = zm_zwolnienie_s; Msg[2] = pvm_mytid(); 10/12
Msg[3] = numer; element.clock = Clock; LicznikPotwierdzen = K - 1; pvm_initsend(pvmdataraw); pvm_pkint(msg,4,1); pvm_bcast("slave", zm_zwolnienie_s); del(kolejkas, element, licznik_s, S); int ZWOLNIENIE_N() int Msg[4]=0; ++Clock; element.id = pvm_mytid(); Msg[0] = zm_zwolnienie_n; Msg[2] = pvm_mytid(); Msg[3] = numer; element.clock = Clock; LicznikPotwierdzen = K - 1; printf(" exit %d\n", pvm_mytid()); pvm_initsend(pvmdataraw); pvm_pkint(msg,4,1); pvm_bcast("slave", zm_zwolnienie_n); del(kolejkan, element, licznik_n, N); void send (int clock, int tid, int type) int Msg[4]=0; Msg[0] = type; Msg[2] = pvm_mytid(); Msg[3] = numer; pvm_initsend(pvmdataraw); pvm_pkint(msg, 4, 1); pvm_send(tid, type); void serwis() while (1) pvm_catchout(stdout); 11/12
int spiolkam = rand()%3+1; sleep(spiolkam); PRZYDZIAL_N(); PRZYDZIAL_S(); ZWOLNIENIE_S(); printf(" JESTEM W NAPRAWIE! %d\n", pvm_mytid()); srand ( time(null) ); spiolkam = rand()%3+1; sleep(spiolkam); receive(); PRZYDZIAL_S(); ZWOLNIENIE_S(); ZWOLNIENIE_N(); int main (int argc, char *argv[]) int myparenttid = -1; setlinebuf(stdout); myparenttid = pvm_parent(); int tids[k]; if (pvm_parent() == PvmNoParent) init(); pvm_catchout(stdout); pvm_spawn("komp_task", NULL, PvmTaskDefault, "", K, tids); pvm_joingroup("master"); pvm_barrier("master", K + 1); pvm_exit(); else init(); //zmienna numer wskazuje, ktory jestem na liscie numer = pvm_joingroup("slave"); pvm_joingroup("master"); pvm_barrier("slave", K ); serwis(); pvm_barrier("master", K+1); 12/12