09.09.2014 Views

Programování v C# - Výjimky a vlákna - eAMOS

Programování v C# - Výjimky a vlákna - eAMOS

Programování v C# - Výjimky a vlákna - eAMOS

SHOW MORE
SHOW LESS

Transform your PDFs into Flipbooks and boost your revenue!

Leverage SEO-optimized Flipbooks, powerful backlinks, and multimedia content to professionally showcase your products and significantly increase your reach.

Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

<strong>Programování</strong> v <strong>C#</strong><br />

<strong>Výjimky</strong> a <strong>vlákna</strong><br />

Petr Vaněček<br />

1 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Obsah přednášky<br />

◮ <strong>Výjimky</strong><br />

◮ Delegáti<br />

◮ Události<br />

◮ Vlákna<br />

2 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Ošetření chyb v programu<br />

◮ Pomocí návratových hodnot funkcí<br />

◮<br />

◮<br />

příklad<br />

void Main (...) {<br />

vysledek = Funkce ();<br />

if( vysledek !=0) {<br />

// došlo k chybě<br />

}<br />

}<br />

nevýhody přístupu<br />

◮ nepřehlednost kódu<br />

◮ složitost kódu<br />

◮ . . .<br />

3 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Použití výjimek<br />

◮ <strong>Výjimky</strong><br />

◮ objekty, které nesou informace o chybovém stavu<br />

◮ Výjimku lze vyhodit kdekoliv v kódu<br />

◮ např. throw new Exception("došlo k chybě")<br />

◮ Výjimku lze odchytit try ... catch bloku<br />

◮<br />

např.<br />

try {<br />

...<br />

} catch ( Exception e) {<br />

...<br />

}<br />

4 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Výhody výjimek<br />

◮ Zpracování výjimek<br />

◮ pokud výjimka nenastane – není ovlivněn výkon<br />

◮ pokud výjimka nastane – časově náročné ošetření<br />

◮ systém výjimek používat na výjimečné situace!<br />

5 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Jazyková konstrukce<br />

try {<br />

◮ try blok<br />

...<br />

◮ začátek bloku s nebezpečným kódem }<br />

◮ catch blok<br />

catch ( IOException )<br />

...<br />

◮ blok s obsluhou výjimek<br />

}<br />

◮ může být uveden několikrát<br />

catch ( Exception e)<br />

◮ může odchytávat<br />

...<br />

◮ konkrétní výjimku<br />

}<br />

◮ konkrétní výjimku a její instanci<br />

catch {<br />

◮ cokoliv<br />

...<br />

◮ finally blok<br />

}<br />

◮ nepovinný<br />

finally {<br />

...<br />

◮ provádí se vždy (i při vyvolání výjimky)<br />

}<br />

6 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Jazyková konstrukce<br />

◮ Výjimkové bloky lze zanořovat<br />

◮ pokud není chyba odchycena, propadává do vnějšího bloku<br />

◮ Při řetězení catch bloku záleží na pořadí<br />

◮ postupovat od speciálních po obecné<br />

◮ Pro všechny výjimky společný předek<br />

◮ Exception<br />

◮ Uživatelské dědit od<br />

◮<br />

ApplicationException<br />

◮ rozlišení výjimek systémových a uživatelských<br />

7 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Co se děje při výjimce<br />

◮ Runtime hledá v aktuální metodě try blok a odpovídající catch bloky<br />

◮ Pokud je blok nalezen, provedou se všechny vnořené finally bloky,<br />

pak se spustí blok catch<br />

◮ Pokud nebyl blok nalezen, prochází se rekurzivně metoda která volala<br />

metodu kde došlo k výjimce<br />

◮ Pokud nebyl nalezen žádný odpovídající blok, povolí se přístup<br />

debuggeru případně dojde k ukončení aplikace<br />

8 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Třída Exception<br />

◮ string Message<br />

◮ vrací řetězec popisující výjimku<br />

◮ Exception InnerException<br />

◮ obsahuje instanci výjimky, která způsobila aktuální výjimku<br />

◮ string StackTrace<br />

◮ vrátí stav zásobníku v době vzniku výjimky<br />

◮ pokud je přeloženo s debug informacemi, vypíší se i názvy souborů a<br />

čísla řádků<br />

at Vyjimky . Vyjimka . Metoda () in h:\ Main .cs: line 18<br />

at Vyjimky . Vyjimka . Main ( String [] args ) in<br />

h:\ Main .cs: line 35<br />

9 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Uživatelské výjimky<br />

◮ Vytváří se kvůli filtrování v catch bloku<br />

◮ Dědit od třídy ApplicatioException<br />

◮ Přidat konstruktory<br />

◮ s parametrem string message<br />

◮ s parametry string message, Exception inner<br />

◮ <strong>Výjimky</strong> většinou neobsahují moc kódu<br />

10 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Co jsou delegáti<br />

◮ Typově bezpečné reference na metody<br />

◮ zapouzdřeno do třídy Delegate, resp. MulticastDelegate<br />

◮ Lze pracovat přímo s třídou Delegate<br />

◮<br />

příliš komplikované<br />

◮ Speciální jazyková konstrukce pro vytváření delegátových typů<br />

11 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Delegátové typy<br />

◮ Deklarace prototypu metody na kterou chceme referenci<br />

◮ typová bezpečnost je zajištěna v definici<br />

◮ určují se typy parametrů, návratové typy<br />

◮ Při vytváření instance delegátového typu se uvádí referencovaná<br />

metoda<br />

◮ musí typově odpovídat deklaraci<br />

◮ Případný modifikátor static je ignorován<br />

◮ metoda může být instanční či statická<br />

12 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Příklad<br />

// deklarace delegátového typu<br />

delegate int Operace ( int x, int y);<br />

class Delegati {<br />

public static int Scitani ( int a, int b) {<br />

return a+b;<br />

}<br />

public static int Nasobeni ( int a, int b) {<br />

return a*b;<br />

}<br />

public static void Main ( string [] args ) {<br />

Operace f1 = new Operace ( Scitani );<br />

Operace f2 = new Operace ( Nasobeni );<br />

}<br />

}<br />

Console . WriteLine (f1 (2 ,3));<br />

Console . WriteLine (f2 (2 ,3));<br />

13 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Násobní delegáti<br />

◮ Třída MulticastDelegate<br />

◮ Umožňuje uchovávat seznam referencí na metody<br />

◮ Vhodný např. pro události – registrace více posluchačů<br />

◮ Deklarace je stejná jako u delegátů<br />

◮ pokud je návratová hodnota void – násobný delegát<br />

◮ v ostatních případech – jednoduchý delegát<br />

◮ Pro násobné delegáty lze použít operátory += a -=<br />

◮ přidání a ubrání reference ze seznamu<br />

14 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Příklad<br />

// deklarace delegátového typu<br />

delegate void Operace ( int x, int y);<br />

class Delegati {<br />

public static void Scitani ( int a, int b) {<br />

Console . WriteLine (a+b);<br />

}<br />

public static void Nasobeni ( int a, int b) {<br />

Console . WriteLine (a*b);<br />

}<br />

public static void Main ( string [] args ) {<br />

Operace f1 = new Operace ( Scitani );<br />

f1 += new Operace ( Nasobeni );<br />

f1 += f1;<br />

f1 -= new Operace ( Nasobeni );<br />

}<br />

f1 (2 ,3);<br />

15 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Událost<br />

◮ Oznámení o změně stavu<br />

◮ volání obslužné funkce<br />

◮ využívají se callback funkce (dynamicky přidělené za běhu)<br />

◮ Zajistí se pomocí delegátů<br />

◮ public delegate void EventHandler(object sender,<br />

EventArgs e)<br />

16 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Vytvoření událostí<br />

◮ Vytvoření třídy parametrů<br />

◮ dědit od EventArgs<br />

◮ Vytvoření delegáta<br />

◮ ve tvaru public delegate void NěcoEventHandler(object<br />

sender, NěcoEventArgs e)<br />

◮ Vytvoření události<br />

◮ ve tvaru public event NěcoEventHandler Něco<br />

◮ Vyvolání události<br />

◮ vhodné otestovat, zda je nějaký posluchač zaregistrován<br />

◮ Zaregistrování posluchačů<br />

◮ pomocí operátorů +=<br />

17 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Příklad<br />

public class KlavesaEventArgs : EventArgs<br />

{<br />

public char klavesa ;<br />

public KlavesaEventArgs ( char klavesa ) {<br />

this . klavesa = klavesa ;<br />

}<br />

}<br />

public delegate void KlavesaEventHandler ( object o,<br />

KlavesaEventArgs args );<br />

18 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Příklad<br />

public class Klavesnice {<br />

public event KlavesaEventHandler Stisknuto ;<br />

public void Start () {<br />

while ( true ) {<br />

ConsoleKeyInfo c = Console . ReadKey ();<br />

if( Stisknuto != null )<br />

Stisknuto (this , new<br />

KlavesaEventArgs (c. KeyChar ));<br />

}<br />

}<br />

}<br />

19 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Příklad<br />

class MainClass<br />

{<br />

public static void Main ( string [] args )<br />

{<br />

Klavesnice k = new Klavesnice ();<br />

k. Stisknuto += new KlavesaEventHandler ( Tisk );<br />

k. Start ();<br />

}<br />

}<br />

public static void Tisk ( object o, KlavesaEventArgs args )<br />

{<br />

Console . WriteLine (" stisknuto ␣ {0} ", args . klavesa );<br />

}<br />

20 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Vlákno a proces<br />

◮ Proces (Process)<br />

◮ z pohledu OS samostatný celek<br />

◮ Vlákno (Thread)<br />

◮ existuje v rámci procesu<br />

21 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Třída Process<br />

◮ Zajišťuje přístup k procesu<br />

◮ umožňuje monitorování a ovládání aplikací<br />

◮ Monitorování<br />

◮ GetProcess...<br />

◮ získá přístup k existujícím procesům<br />

◮ PagedMemorySize<br />

◮ info o přidělené paměti<br />

◮ WaitForExit<br />

◮ čeká na ukončení procesu<br />

◮ Ovládání<br />

◮ Start, Kill<br />

◮ spuštění, ukončení procesu<br />

22 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Třída Thread<br />

◮ Představuje vlákno<br />

◮ Nastavuje vlastnosti<br />

◮ priorita<br />

◮ Background/Foreground<br />

◮ Ovládá vlákno<br />

◮<br />

◮<br />

◮<br />

◮<br />

spuštění<br />

uspání<br />

obnovení<br />

ukončení<br />

◮ . . .<br />

23 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Delegát ThreadStart<br />

◮ void ThreadStart()<br />

◮ Funguje jako vstupní bod <strong>vlákna</strong><br />

Thread t = new Thread ( new TrheadStart ( metoda ));<br />

◮ Po vytvoření vlákno neběží<br />

◮ stav ThreadState.Unstarted<br />

◮ Spouští se metodou Start()<br />

◮ lze zavolat pouze jednou, jinak ThreadStateException<br />

◮ přechází do stavu ThreadState.Running<br />

24 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Stavy <strong>vlákna</strong><br />

◮ Uspání<br />

◮ metoda static void Sleep(int)<br />

◮ může se upsat pouze samo vlákno<br />

◮ Pzastavení<br />

◮ metoda void Suspend()<br />

◮ lze pozastavit z jiného <strong>vlákna</strong><br />

◮ lze znovu spustit metodou void Resume()<br />

◮ Ukončení<br />

◮ metoda void Abort()<br />

◮ výjimka ThreadAbortException<br />

◮ lze odvolat metodou static void ResetAbort()<br />

25 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Další metody a vlastnosti vláken<br />

◮ metoda void Join()<br />

◮ pozastaví volající vlákno, dokud aktuální vlákno neskončí<br />

◮ vlastnost static Thread CurrentThread<br />

◮ vrátí aktuální vlákno<br />

◮ vlastnost bool IsBackground<br />

◮ vrátí/nastaví typ <strong>vlákna</strong><br />

◮ na Foreground <strong>vlákna</strong> se při ukončení aplikace čeká<br />

◮ Background <strong>vlákna</strong> jsou násilně ukončena<br />

◮ vlastnost bool IsAlive<br />

◮ zjistí jestli vlákno ještě pracuje nebo už ne<br />

◮ vlastnost ThreadPriority Priority<br />

◮ zjistí/nastaví prioritu <strong>vlákna</strong><br />

◮ ThreadPriority.Normal,ThreadPriority.Highest, . . .<br />

26 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Skupiny vláken<br />

◮ Třída ThreadPool<br />

◮ Množina background vláken spravovaná systémem<br />

◮ Možnost předat delegáta a data ke zpracování<br />

◮ delegate void WaitCallback(object)<br />

◮ static bool QueueUserWorkItem(WaitCallback,object)<br />

◮ pokud není dostupné vlákno, řadí se požadavek do fronty<br />

◮ Vhodné pro úkoly s minimální interakcí<br />

◮<br />

není dostupná reference na <strong>vlákna</strong><br />

27 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – lock<br />

◮ Automatická synchronizace<br />

◮ Konstrukce lock(výraz) {...}<br />

◮ v závorce – kritická sekce<br />

◮ v KS pouze jedno vlákno<br />

◮ ostatní <strong>vlákna</strong> jsou blokována<br />

◮ Výraz je nejčastěji<br />

◮ this, pokud chceme blokovat instační proměnnou<br />

◮ typeof(třída), pokud chceme blokovat statickou proměnnou<br />

28 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – atribut MethodImpl<br />

◮ Automatická synchronizace<br />

◮ Použití atributu MethodImplAttribute<br />

◮ parametr MethodImplOptions.Synchronized<br />

◮ celá metoda se stává kritickou sekcí<br />

◮ Příklad<br />

[ MethodImpl ( MethodImplOptions . Synchronized )]<br />

public void KritickáSekce ()<br />

{<br />

...<br />

}<br />

29 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – třída Monitor<br />

◮ Ruční synchronizace<br />

◮ Monitor vytváří KS nad celým objektem<br />

◮ Metoda static void Enter(object)<br />

◮ pokus o vstup do KS<br />

◮ pokud není volná, vlákno se zablokuje a čeká na uvolnění<br />

◮ Metoda static bool TryEnter(object)<br />

◮ pokus o vstup do KS<br />

◮ pokud se nepodaří, vrátí false<br />

◮ Metoda static void Exit(object)<br />

◮<br />

◮<br />

výstup z KS<br />

probuzeno jedno čekající vlákno<br />

30 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – třída Monitor<br />

◮ Metoda static bool Wait(object)<br />

◮ uvolní zámek nad objektem<br />

◮ zablokuje se a umístí se do wait fronty monitoru<br />

◮ Metody static void Pulse(object)<br />

a static void PulseAll(object)<br />

◮ upozorní vlákno (<strong>vlákna</strong>) ve wait frontě, že došlo ke změně stavu<br />

31 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – třída Mutex<br />

◮ Ruční synchronizace<br />

◮ Jedno vlákno si může zabrat mutex pro sebe, ostatní jsou blokována<br />

◮ Metoda WaitOne()<br />

◮ pokusí se zabrat si mutex<br />

◮ když není volný, je vlákno blokováno<br />

◮ Metoda ReleaseMutex()<br />

◮ uvolní mutex pro ostatní <strong>vlákna</strong><br />

◮ mutex automaticky dostává další čekající<br />

32 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – třída Interlocked<br />

◮ Ruční synchronizace<br />

◮ Umožňuje atomické operace<br />

◮ Metoda static object CompareExchange(ref object, object,<br />

object)<br />

◮ provede porovnání 1. a 3. parametru a pokud jsou totožné, nastaví<br />

hodnotu 1. parametru na 2.<br />

◮ přetížena pro int a float<br />

◮ Metoda static object Exchange(ref object, object)<br />

◮ nastaví hodnotu 1. parametru na 2.<br />

◮ přetížena pro int a float<br />

◮ Metody static int Increment(ref int)<br />

a static int Decrement(ref int)<br />

◮ atomická inkrementace/dekrementace<br />

◮ přetížené i pro long<br />

33 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – třídy ResetEvent<br />

◮ Třídy ManualResetEvent, AutoResetEvent<br />

◮ Ruční synchronizace<br />

◮ AutoResetEvent volá automaticky Reset po uvolnění posledního<br />

<strong>vlákna</strong> čekajícího na signalizaci po volání metody Set<br />

◮ Metoda bool Reset()<br />

◮ nastaví stav události na nesignalizovanou<br />

◮ Metoda bool WaitOne()<br />

◮ blokuje vlákno dokud není signalizována událost<br />

◮ Metoda bool Set()<br />

◮ nastaví stav události na signalizovanou<br />

◮ probudí čekající <strong>vlákna</strong><br />

34 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Synchronizace – třídy WaitHandle<br />

◮ Ruční synchronizace<br />

◮ Rodič Mutex, Auto a ManualResetEvent<br />

◮ Umožňuje synchronizaci více primitiv<br />

◮ Metoda static bool WaitAll(WaitHandle[])<br />

◮<br />

čeká na všechny<br />

◮ Metoda static int WaitAny(WaitHandle[])<br />

◮ čeká na jedno<br />

35 / 36


Úvod <strong>Výjimky</strong> Delegáti Události Vlákna Konec<br />

Konec<br />

36 / 36

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!