Korutyny Wykład13,str1 tak działa podprogram: PROGRAM GŁÓWNY wywołanie PODPROGRAM tak działają korutyny: KORUTYNA A resume B resume B KORUTYNA B resume A Korutyny Wykład13,str2 Korutyny mają zwykle więcej niż jeden punkt wejścia, otwartych jest naraz kilka korutyn, działa tylko jedna, ale działanie pozostałych jest tylko zawieszone, nie zakończone, korutyna może oddać sterowanie innej korutynie i przejść w stan zawieszenia obliczenia, kiedy znowu uzyska sterowanie, to podejmuje obliczenie od miejsca, w którym poprzednio przerwała, i z dotychczasowymi wartościami zmiennych, sposób współdziałania korutyn to pseudowspółbieżność lub podział czasu
Wykład13,str3 Czynności przy wywołaniu prostego podprogramu: zapisać aktualny stan obliczenia: adres zmiennych lokalnych, wartości rejestrów procesora, stan procesora, itp; wyliczyć parametry i przekazać je podprogramowi; przekazać podprogramowi adres powrotu; oddać sterowanie podprogramowi Czynności przy powrocie z prostego podprogramu: przepisać parametry lokalne do aktualnych(w przypadku wołania przez wynik lub wartość-wynik); jeśli podprogram jest funkcją, to jej wynik przekazać w miejsce dostępne dla programu wywołującego; odtworzyć z zapisów adres zmiennych lokalnych, wartości rejestrów procesora, jego stan, itp; przekazać sterowanie pod zapisany w podprogramie adres powrotu Wykład13,str4 Które z tych czynności ma wykonać program wywołujący, a które podprogram? zapisanie stanu obliczenia wyliczenie parametrów program podgłówny program którykolwiek + przekazanie adresu powrotu + przekazanie sterowania + par formalne do aktualnych + oddanie wyniku funkcyjnego + odtworzenie stanu obliczenia którykolwiek zwrot sterowania +
Wykład13,str5 zmienne lokalne parametry adres powrotu Blok aktywacyjny podprogramu zawiera wartości nienależące do jego kodu Blok aktywacyjny prostego podprogramu(bez rekursji i innych komplikacji) jest tylko jeden i może być alokowany statycznie(w trakcie kompilacji) Organizacja pamięci może być np taka: zmienne lokalne MAIN zmienne lokalne A parametry A adres powrotu A zmienne lokalne B parametry B adres powrotu B kod MAIN koda kodb Wykład13,str6 Parametry i zmienne lokalne dynamiczne na stosie potrzebne np do rekursji; kompilator musi generować kod dla niejawnej alokacji i dealokacji; podprogram potrzebuje wielu bloków aktywacyjnych jednego dla każdego wywołania; zmienne lokalne A parametry A link dynamiczny A adres powrotu A w bloku aktywacyjnym musi znajdować się link dynamiczny informacja, gdzie znajduje się poprzedni blok aktywacyjny Zmienne i parametry skalarne na ogół są wpisane do bloku aktywacyjnego; bardziej skomplikowane dane są czasem reprezentowane w bloku aktywacyjnym przez wskaźniki
Wykład13,str7 Parametry i zmienne lokalne dynamiczne na stosie Dla przykładowej funkcji z C: void sub(double total, int part) { int list[5]; double sum; tak wygląda blok aktywacyjny: lokalna sum lokalna list[4] lokalna list[3] lokalna list[2] lokalna list[1] lokalna list[0] parametr part parametr total link dynamiczny adres powrotu Wykład13,str8 Parametry i zmienne lokalne dynamiczne na stosie potrzebne np do rekursji; kompilator musi generować kod dla niejawnej alokacji i dealokacji; podprogram potrzebuje wielu bloków aktywacyjnych jednego dla każdego wywołania; zmienne lokalne A parametry A link dynamiczny A adres powrotu A w bloku aktywacyjnym musi znajdować się link dynamiczny informacja, gdzie znajduje się poprzedni blok aktywacyjny Zmienne i parametry skalarne na ogół są wpisane do bloku aktywacyjnego; bardziej skomplikowane dane są czasem reprezentowane w bloku aktywacyjnym przez wskaźniki
Wykład13,str9 Parametry i zmienne lokalne dynamiczne na stosie Dla przykładowej funkcji z C: void sub(double total, int part) { int list[5]; double sum; tak wygląda blok aktywacyjny: lokalna sum lokalna list[4] lokalna list[3] lokalna list[2] lokalna list[1] lokalna list[0] parametr part parametr total link dynamiczny adres powrotu Przy każdym wywołaniu podprogramu tworzy się blok aktywacyjny Jego format jest ustalany statycznie, ale on sam powstaje i znika dynamicznie Podprogramy mogą wywoływać się wzajemnie; przy tym program ostatnio wywołany skończy jako pierwszy Dlatego bloki aktywacyjne umieszcza się na stosie Wykład13,str10 Stos: call stack execution stack control stack run-time stack machine stack the stack stos wywołań EP(environment pointer) adres aktualnie czynnego bloku aktywacyjnego
Wykład13,str11 Wywołując podprogram A, program główny musi: 1 utworzyć egzemplarz bloku aktywacyjnego A; 2 zapamiętać stan obliczenia; 3 wyliczyć i przekazać parametry do A; 4 przekazać do A adres powrotu; 5 przekazać do A sterowanie Po wywołaniu podprogramu A musi: 1 zapamiętać stary EP jako link dynamiczny bloku aktywacyjnego i wpisać do EP adres bloku aktywacyjnego; 2 alokować lokalne zmienne Zaraz przed zakończeniem działania podprogram A musi: 1 przepisać wartości param wyjściowych do odp param aktualnych; 2 do EP wpisać link dynamiczny; 3 przekazać sterowanie do programu wywołującego Wykład13,str12 EP: lok zm: y void fun1(double r) { parametry: x ints; linkdyn: adr powr: fun2 lokzm: s parametry: r linkdyn: adrpowr: fun1 lokzm: p parametry: linkdyn: adrpowr: main STOS fun2(s); voidfun2(intx) { inty; intmain() { double p; fun1(p);
Wykład13,str13 EP: lokzm: y parametry: x linkdyn: adr powr: fun2 lokzm: s parametry: r linkdyn: adrpowr: fun1 lokzm: p parametry: linkdyn: adrpowr: main STOS Łańcuch dynamiczny EP oraz wszystkie linki dynamiczne określa zagnieżdżenie aktualnego wywołania funkcji, oraz drogę powrotu do programu głownego Odwołania do zmiennych i parametrów przez lokalne adresy + EP Rekursja tak samo Funkcje dodatkowe pole w bloku aktywacyjnym na wartość zwracaną Wykład13,str14 Ptak konkretny: dziób skrzydła nóżki ogon
Wykład13,str15 Ptak abstrakcyjny: dziób skrzydła nóżki ogon Realizacje ptaki konkretne: Wykład13,str16 Abstrakcja: celowe pomijanie cech drugorzędnych i koncentrowanie się na zasadniczych Abstrakcja upraszcza i zniekształca rzeczywistość Abstrakcyjny typ danych: zestaw wymagań, które ma spełniać typ danych Programista może deklarować zmienne takiego typu, stosować operacje wchodzące w jego skład, nie zajmując się własnościami żadnego konkretnego typu Programy, napisane dla abstrakcyjnego typu danych, będą działać na każdej jego konkretnej realizacji Abstrakcja pomaga opanować złożoność zagadnień przez abstrahowanie od ich cech drugorzędnych Najpopularniejszym stylem programowania z użyciem abstrakcji danych jest programowanie obiektowe
Wykład13,str17 Przykład: stosy M top stack X push empty pop empty: stack push:x stack stack top:stack X pop:stack stack top(push(x, s)) = x pop(push(x, s)) = s Niezależnie od sposobu implementacji stosów, po wykonaniu push(5);push(2);y=top;pop;x=top;pop;push(x-y); naszczyciestosujestliczba3,aresztastosujesttakajaknapoczątku: y =top(push(2,push(5,s)))=2 x = top(pop(push(2, push(5, s)))) = top(push(5, s)) = 5 top(push(x y,pop(pop(push(2,push(5,s))))))=x y =3 pop(push(x y, pop(pop(push(2, push(5, s)))))) = pop(pop(push(2, push(5, s)))) = pop(push(5, s)) = s Wykład13,str18 Przykład: implementacje stosu przez tablice M classstack { private X[] stos; private int ilosc; public Stack() { // konstruktor odpowiada operacji empty stos = new X(duzo); ilosc=0; publicvoidpush(xx) { stos[ilosc]=x; ilosc++; publicxtop() { if(ilosc==0) throw new RuntimeException("stos pusty"); else return stos[ilosc-1]; publicvoidpop() { if(ilosc==0) throw new RuntimeException("stos pusty"); else ilosc--;
Wykład13,str19 Przykład: implementacje stosu przez typ rekursywny Mclass Wezel { private X hd; private Wezel tl; publicwezel(xh,wezelt) {hd=h;tl=t; publicxhead() {returnhd; publicwezeltail() {returntl; class Stack { private Wezel ll; publicstack() {ll=null; publicvoidpush(xx) {ll=newwezel(x,ll); publicxtop() { if(ll==null) throw new RuntimeException("stos pusty"); else return llhead(); publicvoidpop() { if(ll==null) throw new RuntimeException("stos pusty"); else ll=lltail(); Abstrakcyjne typy i hermetyzacja Wykład13,str20 Abstrakcyjny typ danych(specyfikacja zbiorów i własności operacji na nich) składa się z części jawnej(java: public) oraz ukrytej(java: private) Wszystkie implementacje mają taką samą część jawną; jednak funkcje (metody) jawne zwykle są zrealizowane różnie Dla użytkownika nie jest istotne, jak zrealizowano części prywatne Użytkownik nie ma dostępu do części prywatnych, nie może ich śledzić ani zmieniać Części prywatne są hermetycznie zamknięte(encapsulated) to sprzyja modularyzacji Abstrakcyjny typ danych może być parametryzowany np typ X w poprzednich przykładach mógłby być parametrem klasy Stos
Wykład13,str21 Modularyzacja z hermetyzacją ukrywaniem szczegółow WC: pliku nagłówkowym(rozszerzenieh) można wyspecyfikować jawne typy, dane i prototypy definicji funkcji modułu Elementy niejawne modułu zgrupować na niezależnie kompilowanym pliku implementacyjnym(rozszerzeniec) Klientowi dostarczyć plik nagłówkowy oraz skompilowaną wersję pliku implementacyjnego Klient włącza do swojego programu plik nagłówkowy (dyrektywą #include), co zezwala na skompilowanie programu, używającego jawnych elementów modułu, a następnie zlinkowanie przekładu z implementacją modułu To jest dość słaby sposób hermetyzacji modułu