No registered users in community Materiały
in last 10 minutes
in last 10 minutes
Tutorial do symulatora (ALR31S)
# Instalacja symulatora: # # 1. rozpakowac plik symul.zip # 2. uruchomic: ./tclkit konsola2c.tcl # lub: ./tclkit konsola2c.tcl moj_skrypt.tcl # uwaga: symulator wymaga tcl v8.4 lub v8.6 (NIE v8.5 !) # 3. do konsoli wkleic tekst zrodlowy poprzez schowek # klawisze shift+insert (copy), ctrl+insert (paste) # lub wpisac go recznie; # dzialaja tez klawisze do wklejania lub zapisywania plików: # Ctrl+O/S/Z - Open/Save/Undo # 4. uruchamiac fragmenty tekstu zrodlowego: # zaznaczyc fragment + ctrl_enter # lub ustawic kursor na linii + ctrl_enter (uruchamia te linie) # # Uwagi ogolne na temat sumulatora: # # 1. wierzcholki sieci są odizolowane od siebie... # sa interpreterami logicznymi i fiberami # (fiber to inaczej korutina lub "wątek bez wywłaszczania") # # 2. komunikacja wierzcholka "v" z sasiadami: # + wierzchołek posiada następujące zmienne (zm. globalne j. Tcl): # id, id_los, liczbaWierz, stopien, kom(0), kom(1), ... # "kom" to tablica (asocjacyjna) j. Tcl # + zmienna kom(X) zawiera listę komunikatow wysłanych w poprzedniej rundzie # przez sąsiada wierzchołka "v", # poprzez połączenie nr X (nr X z pkt. widzenia "v") # komunikaty z połączenia $i odczytujemy przez $kom($i) w j. Tcl; # istnieje też komenda, ktora zdejmuje pierwszy komunikat z kom(X): # czytaj X # [np. set msg [czytaj $i]] # + komunikaty wysylamy przez połączenie X przy pomocy # wyslij X $msg # [np. wyslij 0 "ABC"; wyslij $i $msg] # # 3. co jeszcze posiada wierzchołek: # + "id_los" to duza liczba wybrana losowo (czyli moga sie powtorzyc!) # + "stopien" to stopien wierzchołka (=liczba sąsiadów) # + komenda "_puts {tekst}" wysyla napisy do okienka output # # 3a. przestarzałe zm./proc., które posiada wierzchołek: # + kom0, kom1, ... zamiast kom(0), kom(1), ... # + "komX_wyslij msg" zamiast "wyslij X msg" # + ... o czym zapomniałem??? # 4. symulacja modelu synchronicznego # + tworzymy tyle fiberow ile jest wierz. sieci # oraz definiujemy program główny: # fiber create $liczbaWierz { # # tutaj program główny # } # UWAGA: warto uzywac procedur, a nie tylko glownego programu! # proc trzeba definiowac we wszystkich fiberach przy pomocy # fiber_iterate { ... def proc ... } # + koniec rundy oznaczamy w kodzie algorytmu przez # fiber yield # + uruchamiamy pojedyncze rundy z konsoli, przy pomocy # fiber yield; runda # 5. symulacja modelu asynchronicznego: # + tworzymy tyle fiberow ile jest wierz. sieci # oraz definiujemy glowny program # + generujemy "zdarzenie obliczeniowe" z konsoli przy pomocy # fiber switchto $id # a zdarzenie to kończy się w kodzie algorytmu przez # fiber switchto main # + generujemy "zdarzenia dostarczenia komunikatu" z konsoli przy pomocy # dostarczKom $id $i # gdzie $i to nr połączenia wierzchołka $id # + istnieje procedura "dostarcz" działająca tak jak "wyslij" # z tą różnicą, że komunikaty są od razu dostarczane # (nie ma potrzeby generowania zdarzenia dostarczenia przez "dostarczKom") # Debugger/uwagi: # # 1. "fiber error" wyswietla stan fiberow; # {} -> fiber dziala # ended -> fiber sie zakonczyl w naturalny sposob # {... opis bledu ...} -> fiber sie zakonczyl z powodu bledu # otrzymujemy liste, po 1 elem dla kazdego fibera # uwaga: każdy fiber ma zm globalną "errorInfo", która zawiera dokładny opis błędu # odczyt: "fiber_eval ID {set errorInfo}", gdzie ID to id fibera z błędem # # 2. zapetlenie sie 1 fibera powoduje zapetlenie calego symulatora # trzeba wtedy "wykilowac" symulator # # 3. aby spowodowac zakonczenie sie fibera, trzeba sprowokowac blad; # np. jesli mamy petle # while {$::run} { # $run dotyczy zm. lokalnej, $::run - zm. globalnej # ... # ... # fiber yield # } # to jesli usuniemy zmienna $run (globalna) to wystapi blad i fiber sie zakonczy!! # mozna to zrobic gdy fiber jest nieczynny np. tak: # fiber_eval ID {unset run}; # ID to id fibera/wierzcholka # set_run qq; # wyrażenie z "qq" jest zawsze błędne # # 4. jesli wszystkie fibery sie zakonczyly (naturalnie lub z powodu bledu) # to mozna usunac fibery (przez "fiber delete") i znów je stworzyć # # 5. jak skutecznie "restartować fibery" ? # trzeba zmusic WSZYSTKIE fibery zeby zakończyły główny program # np. jeśli w warunku pętli jest zm. "run" to wystarczy zrobic: # fiber_iterate {unset run}; fiber yield # # wszystkie fibery powinny się zakończyć z powodu błędu "braku zm. run" # # upewnić się przy pomocy "fiber error" ... # potem wykonać "fiber restart" # przydatna procedura unset_run podobna do set_run, 10.2018: # proc unset_run {} {fiber_iterate {unset ::run}} # # proc ta usuwa zmienne globalne run w fiberach! # # 6. debugger krokowy, nowość 04.2019 (potrzebny nowy symul.zip) !!! # w ten sposób: # fiber_dbg_proc 0 run # instaluje się graficzny debugger dla fibera z id=0 i procedury "run" # !!! UWAGA !!! # kolejną rundę uruchamiać dopiero gdy mamy PEWNOŚĆ # że poprzednia runda się zakończyła (inaczej nastąpi crash...) # # Uwagi dodatkowe: # # 1. mozna uzywac pomocniczych komend fiberowych # fiber_eval $id $kod # wykonuje kod w fiberze $id (na poziomie globalnym) # np: # fiber_eval 0 {set x 123} # # fiber z id==0 bedzie mial zm. globalna x # fiber_iterate $kod # iteruje po wszystkich fiberach i wykonuje kod (na poz. globalnym) # np: # fiber_iterate { proc qqq p {_puts $p} } # # wszystkie fibery beda mialy proc o nazwie qqq # fiber$id eval {... skrypt ...} # wykonuje skrypt w fiberze $id na poziomie bieżącym # (tam gdzie fiber jest zamrożony) # # 2. mozna zmienic glowny program fiberow bez ich usuwania przy pomocy: # fiber code { ... nowy program glowny ...} # # jednak nowy program glowny zacznie obowiazywac dopiero # # gdy wszystkie fibery zakancza stary program glowny! # # 3. model asynch./ proc pomocnicza czytajKomTypu # proc czytajKomTypu {typ nrPol} # czeka na komunikat typu $typ z polaczenia $nrPol # (chyba ze podamy * co oznacza dowolny typ/nr polaczenia) # typ komunikatu to pierwsze słowo listy, która jest komunikatem # (np dla komunikatu {Q 123} typem jest "Q") # zwracany jest cały komunikat, razem z typem # komunikat jest usuwany ze zmiennej kom$nrPol (lub innej) # można podać jako 3 param. nazwę zm. w której otrzymamy nr poł. # (o ile $nrPol=="*"; np czytajKomTypu Q * nrpol) # UWAGA: ta proc nie we wszystkich algorytmach asynch jest przydatna... # # Problemy z j. Tcl (patrz też tutorial j. Tcl): # # 1. jak zadeklarować zmienne globalne w procedurze ? # proc p1 {} { # global zm_glob; puts $zm_glob # } # proc p1 {} { # puts $::zm_glob; # nie deklarujemy, tylko "nazwa kwalifikowana" zmiennej # } # # 2. kłopoty z konsola2c.tcl (10.2018) # jeśli nie widać selekcji to wykonaj kod w konsoli: # .konsola.t config -selectborderwidth 1 # jeśli nie działają klawisze Ctrl/Shift+Ins (copy/paste) to wtedy # zobaczyć jakie klawisze powodują copy/paste; z konsoli wykonać: # event info <<Copy>> # event info <<Paste>> # # --- # Przyklad symulacji modelu synchronicznego # + w tym przykładzie po sieci krąży token zawierający zmienną typu "int", # której wartość zwiększa się o 1 po każdym skoku ... # source symul_lib.tcl; # ladowanie symulatora # tworzymy graf komunikacyjny (w tym wypadku cykl) set liczbaWierz 5 set sasiedzi(0) {4 1} set sasiedzi(1) {0 2} set sasiedzi(2) {1 3} set sasiedzi(3) {2 4} set sasiedzi(4) {3 0} # główny program na każdym wierzchołku/fiberze... fiber create $liczbaWierz { if {$id==0} {wyslij 1 0} fiber yield; # oznacza koniec rundy while {$run} { # zmienna run pozwala zakonczyć działanie symulacji if {$kom(0)!=""} { set x $kom(0) incr x wyslij 1 $x } fiber yield; # oznacza koniec rundy } } Inicjalizacja; # koniecznie trzeba to wywołać !!! proc wizualizacja {} { fiber_iterate {_puts "$id: $kom0, $kom1"} # petla fiber_iterate iteruje po wszystkich fiberach # proc wizualizacja wywolujemy z konsoli po kazdej rundzie } # !!! do tego miejsca wszystko wykonać !!!!!!!!!!!!!!!!!!!!! fiber yield; runda; wizualizacja # wykonuje kolejna runde... # procedura runda dostarcza wysłane komunikaty if 0 { # to się czasem przydaje: set_run 0; fiber yield; runda; set_run 1; fiber delete # usuwanie fiberów set_run 0; fiber yield; runda; set_run 1; fiber restart # restart kodu fiberów fiber error # wyświetla stan fiberów ({}, ended, error) fiber_eval 0 {set id} # wykonanie kodu w fiberze 0 # UWAGA: fiber_eval wykonuje kod na poziomie globalnym # "fiber0 eval {set id}" wykonuje kod tam gdzie fiber zostal zamrozony... } # --- # Przyklad symulacji modelu asynchronicznego # + w tym przykladzie wierz. wysylaja i przekazuja # komunikaty postacai "Q $id_los" # source symul_lib.tcl set liczbaWierz 20 iterate i $liczbaWierz { # petla "iterate i 10" iteruje od 0 do 9 let i1 $i-1; if {$i1==-1} {let i1 $liczbaWierz-1} let i2 $i+1; if {$i2==$liczbaWierz} {let i2 0} set sasiedzi($i) "$i1 $i2" } fiber create $liczbaWierz { wyslij 1 "Q $id_los" fiber switchto main while {$run} { if {$kom(0)!=""} { set x [czytaj 0] wyslij 1 $x } fiber switchto main } } InicjalizacjaAsynch proc wizualizacja {} { fiber_iterate {_puts "$id, $id_los, $lider; $kom0, $kom1"} } # ... do tego miejsca mozna wszystko wykonac if 0 { zakonczFibery; fiber delete zakonczFibery; fiber restart fiber error zaproponuj pokazKom set licznikKom } fiber switchto 8; pokazKom dostarczKom 9 0; pokazKom fiber switchto 9; pokazKom # + tworzymy egzekucje ... # (tj. ciag zdrzen: "obliczeniowych" i "dostarczenia komunikatu") # + "fiber switchto nr_wierz" - to zdarzenie obliczeniowe # + "dostarczKom nr_wierz nr_kabla" - to zdarzenie dostarczenia komunikatu # + "pokazKom" to proc. wizualizacyjna, pokazująca stan wszystkich połączeń # --- # Przyklad 2 symulacji modelu asynchronicznego # + jest to alg. wyboru lidera, uzywajacy O(n^2) komunikatow # + UWAGA! w symulatorze asynch. wierzchołki powinny pracować "w nieskończoność" # symulację wył. "ręcznie" gdy stwierdzimy, że nie wysyła się już żadnych komunikatów ... # source symul_lib.tcl set liczbaWierz 20 iterate i $liczbaWierz { # petla "iterate i 10" iteruje od 0 do 9 let i1 $i-1; if {$i1==-1} {let i1 $liczbaWierz-1} let i2 $i+1; if {$i2==$liczbaWierz} {let i2 0} set sasiedzi($i) "$i1 $i2" } fiber create $liczbaWierz { set lider {} wyslij 1 "LE $id_los" while {$run} { set id0 [lindex [czytajKomTypu LE 0] 1] if {$id0>$id_los} { wyslij 1 "LE $id0" } elseif {$id0==$id_los} { set lider 1; wyslij 1 "LE -1" } elseif {$id0==-1 && $lider=={}} { set lider 0; wyslij 1 "LE -1" } } } InicjalizacjaAsynch proc wizualizacja {} { fiber_iterate {_puts "$id, $id_los, $lider; $kom0, $kom1"} } # ... do tego miejsca mozna wszystko wykonac if 0 { zakonczFibery; fiber delete zakonczFibery; fiber restart fiber error zaproponuj pokazKom set licznikKom } fiber switchto 8; pokazKom dostarczKom 9 0; pokazKom # + tworzymy egzekucję ... # --- ## dokumentacja wyciągnięta z pliku symul_lib.tcl (!!! niedokończone !!!) # # koniec rundy zaznaczamy przez "fiber yield" # wierz stopnia np 3 ma incydentne kraw oznaczone przez: # kom0, kom1, kom2 # kazda incydentna kraw nr X ma 2 zmienne: # komX - zawiera komunikat wyslany przez sasiada w poprzedniej rundzie # komX_pisz - tu jest umieszczany komunikat wyslany przez sasiada w biezacej rundzie # Uwaga: # komX to lista komunikatow, a nie pojedynczy komunikat!!! # (jesli komunikat nie ma spacji to lista sie nie rozni # od pojedynczego komunikatu!!! to moze byc przyczyna bledow...) # proc komX_wyslij komunikat # sluzy do wysylania komunikatu przez kraw nr X # np # kom${i}_wyslij "A ku ku" # kom1_wyslij $x # proc komX_dostarcz komunikat (16.11.2009) # wysyla i dostarcza komunikat... # proc wyslij {doKogo co args} # wysyla komunikat przez polaczenie nr doKogo # np: wyslij $i "A ku ku" # podobnie dziala dostarcz (16.11.2009) # proc czytaj {odKogo args} # odbiera komunikat z polaczenia nr odKogo # w args moze byc opcja -podgraf {lista nr polaczen} # komendy wyslij/czytaj to interf. "wyzszego poziomu" # umozliwia pewne uogolnienia, np dzialania na podgrafie: # wyslij 0 "123" -podgraf {2 3}; # wysyla przez pol. nr 2 # czytaj 1 -podgraf {3 4}; # odczytuje z pol. nr 4 # !!! jeszcze nie zaimplementowane !!! # 16.11.2009 - zmiana dzialania: # czytaj pobiera komunikat z komX, jako kolejki komunikatow # proc. pomocnicze w konsoli: # DodajKraw # Inicjalizacja # runda # set_run # fiber_iterate # fiber_eval # proc. pomocnicze w fiberze: # iterate zm liIter kod # iterate1 zm liIter kod; # robi liIter-1 iteracji od 1 !!! # let # comment ## model asynch z osobnymi zdarzeniami obl. i dostarczania (19.10.2009) # * wysylanie komunikatu przy pomocy: # komX_wyslij msg # * dostarczone komunikaty sa dostepne w zmiennych komX; # oczekiwanie na dostarczenie komunikatu okreslnego typu: # czytajKomTypu {typ nrPolaczenia} # zaklada sie ze komunikat to lista >=2 elementowa, pierwsze slowo to typ # jesli brak potrzebnego komunikatu to proc wykonuje "fiber switchto main" # * generowanie zdarzenia obliczeniowego: # fiber switchto procesor # * generowanie zdarzenia dostarczenia komunikatu: # dostarczKom procesor nrPolaczenia # przemieszcza komunikaty z komX_pisz do komX # * podglad dostepnych komunikatow: # pokazKom # * proc pomocnicze: # zakonczFibery # zaproponuj # proponuje zdarzenia ktore cos zmienia... # proc czytajKomTypu {typ nrPolaczenia {varNrPol ""}} # zaklada sie ze w kazdym komunikacie pierwsze slowo to typ... # mozna podac "*" jako nrPolaczenia i/lub typ !!! # rzeczywisty nr jest zwracany przez (opcjonalny) varNrPol