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
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