1/39 Ada Erlang Vláknové programování část XI Lukáš Hejmánek, Petr Holub {xhejtman,hopet}@ics.muni.cz Laboratoř pokročilých síťových technologií PV192 2010–05–06 2/39 Ada Erlang Přehled přednášky Ada Základy jazyka Paralelní programování Erlang 3/39 Ada Erlang Ada     “Regression testing?” What’s that? If it compiles, it is good, if it boots up it is perfect. – Linus Torvalds     Compilable but broken code is even worse than working code. – Alan Cox during a bright moment on the linux-kernel list     Ada: Ideally, when compiles fine it also runs fine. 4/39 Ada Erlang Ada Ada 83/95/2005 jazyk orientovaný na spolehlivé aplikace: vojáci, letectví, ... WORM: write once read many silně typovaný jazyk podpora paralelismu enkapsulace, výjimky, objekty, správa paměti, atd. GNAT ◾ volně dostupný překladač, frontend k GCC materiály na webu ◾ (Annotated) Reference Manual http://www.adaic.org/standards/ada05.html ◾ http://stwww.weizmann.ac.il/g-cs/benari/books/index.html#ase ◾ http://en.wikibooks.org/wiki/Programming:Ada ◾ http://www.adahome.com/Tutorials/Lovelace/lovelace.htm ◾ http://www.pegasoft.ca/resources/boblap/book.html 5/39 Ada Erlang Ada: Hello World! 1 with Ada.Text_IO; 3 procedure Hello is begin 5 Ada.Text_IO.Put_Line ("Hello, world!"); end Hello; normální kompilace gnatmake hello.adb přidané kontroly gnatmake -gnatya -gnatyb -gnatyc -gnatye -gnatyf -gnatyi -gnatyk -gnatyl -gnatyn -gnatyp -gnatyr -gnatyt -g -gnato -gnatf -fstack-check hello.adb 6/39 Ada Erlang Ada: typy Základní typy ◾ celočíselné, plovoucí, decimální ◾ výčty ◾ pole ◾ záznamy (struktury) ◾ ukazatele (access) ◾ úlohy (tasks) ◾ rozhraní (interfaces) Y : Boolean; 2 S : String; F : Float; 4 Addr : System.Address; type uhel is delta 1 / (60 * 60) range 0.0 .. 360.0; 6 type teplomer is delta 10.0**(-2) digits 10 range -273.15 .. 5000.0; type pole is array (1 .. 10) of Natural; 8 X : String (1 .. 10) := (others => ’ ’); type Enum is (A, B, C); 10 E : Enum := A; 7/39 Ada Erlang Ada: typy Anonymní vs. pojmenované typy X : String (1 .. 10) := (others => ’ ’); 2 subtype My_String is String (1 .. 10); Y : My_String := (others => ’ ’); Privátní versus limitované privátní typy type typ_X is private; -- nevidime dovnitr 2 type typ_X is limited private; -- nelze priradit 8/39 Ada Erlang Ada: typy Záznamy / Struktury 1 type Car is record Identity : Long_Long_Integer; 3 Number_Wheels : Positive range 1 .. 10; Paint : Color; 5 Horse_Power_kW : Float range 0.0 .. 2_000.0; Consumption : Float range 0.0 .. 100.0; 7 end record; 9 BMW : Car := (Identity => 2007_752_83992434, 11 Number_Wheels => 5, Horse_Power_kW => 190.0, 13 Consumption => 10.1, Paint => Blue); Variantní záznamy, uniony 9/39 Ada Erlang Ada: typy Objekty – tagované záznamy 1 type Person is tagged record 3 Name : String (1 .. 10); Gender : Gender_Type; 5 end record; 7 type Programmer is new Person with record 9 Skilled_In : Language_List; end record; 11 function Get_Skills (P : Programmer) return Language_List; 10/39 Ada Erlang Ada: typy Typy vs. podtypy type Integer_1 is range 1 .. 10; 2 subtype Integer_2 is Integer_1 range 7 .. 11; A : Integer_1 := 8; 4 B : Integer_2 := A; -- OK 6 type Integer_1 is range 1 .. 10; type Integer_2 is new Integer_1 range 2 .. 8; 8 A : Integer_1 := 8; B : Integer_2 := A; -- nelze! 10 C : Integer_2 := Integer_2 (A); -- OK 11/39 Ada Erlang Ada: typy Ukazatele type Day_Of_Month is range 1 .. 31; 2 type Day_Of_Month_Access is access Day_Of_Month; type Day_Of_Month_Access_All is access all Day_Of_Month; 4 for Day_Of_Month_Access’Storage_Pool use Pool_Name; procedure Test (Call_Back: access procedure (Id: Integer; Text: String)); 6 DoM : Day_Of_Month; 8 DoMA : Day_Of_Month_Access := Dom’Access; -- neee DoMAA : Day_Of_Month_Access_All := Dom’Access; -- jo 10 DoMA : Day_Of_Month_Access := new Day_Of_Month; 12 procedure Free is new Ada.Unchecked_Deallocation (Object => Day_Of_Month 14 Name => Day_Of_Month_Access); Free (DoMA); 12/39 Ada Erlang Ada: typy Atributy type barvy is (cervena, zelena, modra); 2 barvy’Pos(cervena) -- = 0 barvy’Val(0) -- = cervena 4 type pole is array (1 .. 10) of Natural; pole’First -- = 1 6 pole’Last -- = 10 pole’Range -- = 1 .. 10 8 type Byte is range -128 .. 127; for Byte’Size use 8; 10 Byte’Min -- = -128 Byte’Max -- = 127 12 F : Float; F’Ceiling; 14 F’Floor; F’Rounding; 16 F’Image -- Float -> String Float’Val -- String -> Float 13/39 Ada Erlang Ada: řídící struktury 1 if condition then statement; 3 else other statement; 5 end if; 7 case X is when 1 => 9 Walk_The_Dog; when 5 => 11 Launch_Nuke; when 8 | 10 => 13 Sell_All_Stock; when others => 15 Self_Destruct; end case; 17 Until_Loop : 19 loop X := Calculate_Something; 21 exit Until_Loop when X > 5; end loop Until_Loop; 23 for I in X’Range loop 25 X (I) := Get_Next_Element; end loop; 14/39 Ada Erlang Ada: výjimky package body Directory_Enquiries is 2 procedure Insert (New_Name : in Name; 4 New_Number : in Number) is 6 begin if New_Name = Old_Entry.A_Name then 8 raise Name_Duplicated; end if; 10 New_Entry := new Dir_Node’(New_Name, New_Number,); exception 12 when Storage_Error => raise Directory_Full; end Insert; 14 procedure Lookup (Given_Name : in Name; 16 Corr_Number : out Number) is 18 begin if not Found then 20 raise Name_Absent; end if; 22 end Lookup; 24 end Directory_Enquiries; 15/39 Ada Erlang Ada: procedury, funkce procedury: in, out a in out parametry funkce: pouze in parametry, vrací hodnotu 1 procedure Procedura (A, B : in Integer := 0; C : out Unbounded_String; 3 D : in out Natural) is 5 begin C := To_Unbounded_String(A’Image & " " & B’Image); 7 D := D + 1; end Procedura; 9 function Funkce (A, B: Integer) return String 11 is Retezec : Unbounded_String; 13 Prirozene_Cislo : Natural; begin 15 Procedura (A, B, Retezec, Prirozene_Cislo); Procedura (Retezec, Prirozene_Cislo); 17 Procedura (B => B, A => A, Retezec, Prirozene_Cislo); return To_String (Retezec); 19 end Funkce; 21 type Callback_Procedury is access procedure (Id : Integer; T : String); type Callback_Function is access function (Id : Natural) return Natural; 16/39 Ada Erlang Ada: balíky Princip zabalení ◾ rozdělení funkcionality do balíků (packages) ◾ hierarchie balíků: child packages (Ada95) ◾ privátní část (balíků, chráněných typů) Princip oddělení specifikace a implementace ◾ .ads popisuje rozhraní lze kompilovat i jen proti specifikaci (bez implementace), ale nelze v takovém případě linkovat ◾ .adb je implementace Doporučené pojmenování souborů podle jmen balíků ◾ s/\./-/g Nejsou požadavky na adresářovou strukturu Možnost externalizace implementací balíků 17/39 Ada Erlang Ada: balíky balik.ads: package Balik is 2 type Muj_Typ is private; 4 procedure Nastav_A (This : in out Muj_Typ; 6 An_A : in Integer); 8 function Dej_A (This : Muj_Typ) return Integer; 10 private 12 type Muj_Typ is record 14 A : Integer; end record ; 16 pragma Inline (Dej_A); 18 end Balik; 18/39 Ada Erlang Ada: balíky balik.adb: 1 package body Balik is 3 procedure Nastav_A (This : in out Muj_Typ; An_A : in Integer) 5 is begin 7 This.A := An_A; end Set_A; 9 function Dej_A (This : Muj_Typ) return Integer is 11 begin return This.A; 13 end Get_A; 15 end Balik; 19/39 Ada Erlang Ada: Tasks, Rendezvous Koncept CSP: Communicating Sequential Processes ◾ Hoare, 1978 ◾ paralelně běžící sekvenční procesy ◾ komunikace: zasílání zpráv ◾ synchronizace: synchronní zasílání zpráv odesílatel se zablokuje, dokud příjemce není schopen přijmout zprávu příjemce se zablokuje, dokud není schopen od odesílatele přijmout zprávu 20/39 Ada Erlang Ada: Tasks, Rendezvous 21/39 Ada Erlang Ada: Tasks task ◾ lokálně definované běží od začátku rozsahu, v němž jsou definované ◾ dynamicky alokované access typ alokace pomocí new běží až od alokace ◾ pole tasků ukončování ◾ spontánní ◾ abort 22/39 Ada Erlang Ada: Tasks 1 task T is end T; 3 task body T is 5 begin makam; 7 end T; 9 task type T_Type is end T; 11 task body T_Type is 13 begin loop 15 makam; end loop; 17 end T_Type; 19 Pole_T : array (1..10) of T_Type; 21 type T_Type_Access is access T_Type; Dynamicky_T : T_Type_Access; 23 Dynamicky_T := new T_Type; 23/39 Ada Erlang Ada: Rendezvous místa synchronizace – předávání dat entry ◾ deklarace rendezvous bodu ◾ in, out, in out parametry accept ◾ implementace v těle tasku 24/39 Ada Erlang Ada: Tasks, Rendezvous 1 procedure Task1 is 3 task Vlakno is entry ZadejX (X : in Integer); 5 entry PrectiX (X : out Integer); end Vlakno; 7 task body Vlakno is 9 Hodnota : Integer; begin 11 accept ZadejX (X : in Integer) do Hodnota := X; 13 end ZadejX; Hodnota := Hodnota + 1; 15 accept PrectiX (X : out Integer) do X := Hodnota; 17 end PrectiX; end Vlakno; 19 Chci_Inkrementovat : Integer; 21 begin 23 Vlakno.ZadejX(Chci_Inkrementovat); Vlakno.PrectiX(Chci_Inkrementovat); 25 end Task1; 25/39 Ada Erlang Ada: Rendezvous select ◾ výběr z více accept možností 1 task body T is begin 3 loop select 5 accept Rande1 do neco; 7 end Rande1; or 9 accept Rande2 do neco; 11 end Rande2; neco; 13 accept Rande3 do neco; 15 end Rande3; or 17 terminate; end loop; 19 end T; 26/39 Ada Erlang Ada: Rendezvous select ◾ časovaný výběr 1 task body T is begin 3 loop select 5 accept Rande1 do neco; 7 end Rande1; or 9 delay 10.0; taky_neco; 11 end select; end loop; 13 end T; 27/39 Ada Erlang Ada: Rendezvous select ◾ časovaný výběr 1 task body T is begin 3 loop select 5 accept Rande1 do neco; 7 end Rande1; else -- ekvivalent "or delay 0.0" 9 null; -- busy waiting end select; 11 end loop; end T; 28/39 Ada Erlang Ada: pokročilé paralelní programování předávání parametrů při vzniku vlákna ◾ parametrizace vlákna entry families ◾ prioritizace a odlišení volajících vláken Real-Time and Distributed Systems Annex ◾ (dynamické) priority vláken při volání entries ◾ monotónní hodiny s vysokou přesností ◾ restrikce tasků pro speciální případy (Ravenscar profile) ◾ preemptivní abort ◾ mnoho dalšího 29/39 Ada Erlang Ada: atomické a volatilní proměnné pragma Atomic (); ◾ zajišťuje atomické aktualizace proměnných Prirozene_Cislo : Natural; 2 pragma Atomic (Prirozene_Cislo); pragma Atomic_Components (); ◾ zajišťuje atomické aktualizace součástí složeného typu record type Byte is range 0 .. 255; 2 for Byte’Size use 8; type Moje_Struktura is 4 record B1 : Byte; 6 B2 : Byte; B3 : Byte; 8 B4 : Byte; end record; 10 pragma Atomic_Components (Moje_Struktura); 30/39 Ada Erlang Ada: atomické a volatilní proměnné pragma Volatile (); ◾ upozornění pro kompilátor, že se hodnoty proměnných mohou neočekávaně měnit ◾ zejména kompilátor musí zamezit optimalizacím, které by mohly interferovat Buffer_Zarizeni : Integer; 2 pragma Volatile (Buffer_Zarizeni); pragma Volatile_Components (); ◾ totéž pro komponenty složeného typu record 31/39 Ada Erlang Ada: Protected Types – monitory Implementace monitorů ◾ funkce – nemohou měnit data procedury – mohou měnit data entry – strážený vstup, mohou měnit data ◾ efektivní paralelizace: podobne ReadWriteLocku v Javě funkce mohou přistupovat paralelně procedury a entries musí pracovat exkluzivně protected type Muj_Typ is 2 procedure Nastav_hodnotu (n : Integer); procedure Odnastav_hodnotu; 4 function Zjisti_hodnotu return Integer; entry Pockej_na_nastaveni (n : Integer); 6 private Hodnota : Integer; 8 Nastaveno : Boolean := False; end Muj_Typ; 32/39 Ada Erlang Ada: Protected Types – monitory 10 protected body Muj_Typ is procedure Nastav_hodnotu (n : Integer) is 12 begin Hodnota := n; 14 Nastaveno := True; end Nastav_hodnotu; 16 procedure Odnastav_hodnotu is 18 begin Nastaveno := False; 20 end Odnastav_hodnotu; 22 function Zjisti_hodnotu return Integer is begin 24 return Hodnota; end Zjisti_hodnotu; 26 entry Pockej_na_nastaveni 28 when Nastaveno is begin 30 null; end Pockej_na_nastaveni; 32 end Muj_Typ; 33/39 Ada Erlang Ada: Guarded Entries chránění dle privátního stavu protected type Chraneno_Stavem is 2 entry Vstup; private 4 I : Integer; end Chraneno_Stavem; 6 protected body Chraneno_Stavem is 8 entry Vstup when I > 0 is begin 10 null; end Vstup; 12 end Chraneno_Stavem; ◾ používat pouze privátní proměnné ◾ např. implementace mutexů a semaforů ◾ requeue zařazení volání privátní entry volání sebe sama vnitřní vs. vnější kruh entry 34/39 Ada Erlang Ada: Guarded Entries chránění dle atributů 1 protected type Chraneno_Stavem is entry Vstup; 3 private I : Integer; 5 end Chraneno_Stavem; 7 protected body Chraneno_Stavem is entry Vstup when Vstup’Count > 4 is 9 begin null; 11 end Vstup; end Chraneno_Stavem; ◾ atribut E’Count vrátí počet zablokovaných vláken na vstupu do entry E ◾ např. implementace bariér 35/39 Ada Erlang Ada: Asynchronous Transfer of Control Časově omezený běh 1 select -- triggering_statement 3 delay 5.0; -- post_trigger_part 5 Put_Line ("Tudy cesta nevede!"); then abort 7 -- abortable_part Prevelevelmidlouhe_Volani; 9 end select; ◾ pokud abortable_part doběhne dříve než triggering_statement, pokusí se ukončit triggering_statement ◾ pokud triggering_alternative doběhne dřív než abortable_part, je abortable_part ukončena a provede se část post_trigger_part ◾ triggering_statement – v Ada 95 entry, v Ada 2005 i procedury 36/39 Ada Erlang Erlang: distribuované programování Erlang ◾ funkcionální programovací jazyk pro paralelní a distribuované programování ◾ An Erlang Course http://www.erlang.org/course/course.html ◾ http://www.erlang.org/doc/reference_manual/ processes.html ◾ skutečně použitelný: např. ejabberd vytvoření procesu spawn(Modul, Exportovana_fce, Seznam_argumentu) předávání zpráv PID_procesu ! zprava receive zprava -> udelej_neco registrace procesů register(nejaky_atom, PID) whereis(registrovane_jmeno) 37/39 Ada Erlang Erlang: distribuované programování -module (priklad). 2 -compile(export_all). 4 klient(Pid) -> Pid ! {self(),pozadavek,ping}, 6 receive {Pid,odpoved,Odpoved} -> 8 io:format("dorazila odpoved ~p~n",[Odpoved]), Pid ! exit 10 end, io:format("klient skoncil~n"). 12 server() -> 14 receive {Od,pozadavek,Pozadavek} -> 16 io:format("obdrzel jsem pozadavek ~p od ~p~n", [Pozadavek, Od]), 18 sleep(1000), Od ! {self(),odpoved,pong}, 20 server(); _ -> 22 io:format("server skoncil~n") end. 38/39 Ada Erlang Erlang: distribuované programování sleep(Time) -> 26 receive after Time -> void 28 end. 30 spust() -> Pid = spawn(fun server/0), 32 spawn(fun() -> klient(Pid) end), io:format("spusteni server i klient~n", []). -bash-2.05b$ erl Erlang (BEAM) emulator version 5.5.2 [source] [async-threads:0] [hipe] Eshell V5.5.2 (abort with ^G) 1> c(priklad). {ok,priklad} 2> priklad:spust(). spusteni server i klient obdrzel jsem pozadavek ping od <0.37.0> ok dorazila odpoved pong klient skoncil server skoncil 39/39 Ada Erlang Erlang: distribuované programování Svázené (linked) procesy link(Pid) -> true spawn_link(Modul, Exportovana_fce, Seznam_argumentu) unlink(Id) -> true ◾ pokud umře proces, pošle o tom zprávu všem, kteří jej mají ,,nalinkovaný‘‘ {’EXIT’, FromPid, Reason} Monitorování procesů erlang:monitor(process, registrovane_jmeno) ◾ alternativa k použití linků ◾ při ukončení procesu zašle zprávu {’DOWN’, Ref, process, Pid2, Reason} ◾ vícenásobné volání vytvoří více monitorů Zachytávání Exit signálů process_flag(trap_exit,true) ◾ při exitu vygeneruje zprávu jako u linků