Podpora vláken a jejich synchronizace v jazyce C# Jan Kučera Jan Mittner Petr Effenberger 4IT353 Klient/server aplikace v Javě
Obsah Představení jazyka C# Rozdíly C# oproti Javě .NET Framework Vlákna v C# Synchronizace Shrnutí
Jazyk C# Striktně objektově orientovaný jazyk Vše je objekt Neumožňuje přístup do paměti Umožňuje však rozlišení řízeného a neřízeného kódu (využití kódu napsaného např. v C nebo C++) Garbage Collector (podobně jako v Javě) Založený na jazycích Visual C++, Java, Delphi Vyvinut společností Microsoft Má ISO normu (ISO/IEC 23270) Hlavní programovací jazyk pro platformu.NET Framework V porovnání s ostatními.NET jazyky má největší možnosti.NET1.0,.NET 1.1,.NET 2.0,.NET 3.0,.NET 3.5 V souvislosti s rozvojem.NET frameworku se rozvíjí i C# Podstatné rozšíření v.NET 2.0 (genericita, nulovatelné typy, neúplné třídy, anonymní metody, …)
Rozdíly C# oproti Javě (1) Rozdílné konvence a pojmenování některých klíčových slov např. sealed – final, bool – boolean, internal – proteced, lock – synchronized, namespace – package, using – import C# umožňuje předávání parametrů nejen hodnotou (jako v Javě), ale i odkazem (referencí) C# umožňuje definovat třídu na více místech (partial class), výhodné pro generování GUI pomocí IDE C# nabízí nulovatelné typy int? pocet = null; pocet = 10; if (pocet.HasValue) { // příkazy }
Rozdíly C# oproti Javě (2) C# umožňuje používat delegáty „objektové zapouzdření odkazů na metody“, v C++ obdobou ukazatele na funkce delegáty se využívají hojně také ve vícevláknových aplikacích delegate bool Filter(char c); public static bool IsDigit(char c) { // příkazy } Filter f = new Filter(IsDigit); if (f(c)) { // příkazy }
Rozdíly C# oproti Javě (3) C# pracuje s tzv. vlastnostmi (properties) – obdoba getterů a setterů v Javě private int pocet; public int Pocet { get { // zde mohou být další příkazy // obdobně jako v getteru v Javě return pocet; } set { // zde mohou být další příkazy // obdobně jako v setteru v Javě pocet = value; }
.NET Framework Platforma společnosti Microsoft pro tvorbu aplikací Aplikace primárně určené pro Windows Aplikace serverové, klientské, pro mobilní zařízení nebo embedded Podpora vývoje webových aplikací a webových služeb Architektura Programovat se dá v řadě jazyků – C#, J#, Visual Basic, C++... (mnoho jazyků jsou jazyky implementované třetími stranami – Haskell, Mercury, Smalltalk...) Common Language Infrastructure Kód napsaný v jakémkoli podporovaném jazyce se přeloží do CIL (Common Intermediate Language) Common Language Runtime přeloží kód z Common Intermediate Language do binárního kódu spustitelného na dané platformě
Vlákna v jazyce C# Namespace System.Threading Namespace odpovídají balíčkům v Javě. Namespace System je obdobou java.lang. Tento namesapce obsahuje třídy a rozhraní pro podporu programování vícevláknových aplikací. Základní třída pro tvorbu vláken System.Threading.Thread – třída představující vlákno Metoda Start – spustí vlákno Metoda Sleep – uspí na zadaný počet milisekund běžící vlákno (volat může pouze samo vlákno) Metoda Suspend – pozastavení vlákna (lze volat i z jiného vlákna) Metoda Resume – opětovné spuštění pozastaveného vlákna Metoda Join – vlákno může čekat na skončení jiného vlákna Metoda Abort – předčasné ukončení vlákna (výjimka ThreadAbortException, lze odvolat metodou ResetAbort) Vlastnost ThreadState – aktuální stav vlákna Vlastnost IsBackground (vrátí/nastaví typ vlákna) Vlastnost Priority (vrátí/nastaví prioritu vlákna)
Spuštění části kódu v samostatném vlákně V samostatném vlákně může běžet jakákoli metoda Vytvoří se instance třídy Thread, v konstruktoru se jí předá delegát, jehož parametrem je metoda, která má běžet v samostatném vlákně. Příklad vytvoření vlákna: Metoda, která se má v novém vlákně spustit: public static void DoWork() { for (int i = 0; i < 100; i++) { Console.WriteLine("Child Thread: " + i); } Vytvoření a spuštění vlákna: Thread childThread = new Thread(new ThreadStart(DoWork)); childThread.Start(); for (int i = 0; i < 100; i++) { Console.WriteLine("Main Thread: " + i); }
Synchronizace pomocí Monitoru System.Threading.Monitor – pomocí monitoru je možné vláknu udělit zámek pro přístup k objektu nebo jeho části (části kódu): Podobné jako synchronized v Javě: lock (výraz){ // příkazy kritické sekce } Nejčastěji používaným výrazem je: this - pokud chceme blokovat instanční proměnnou typeof(Třída) – pokud chceme blokovat statickou proměnnou Pokud je kritickou sekcí celá metoda, pak se nepoužívá klíčové slovo lock, ale atribut: [MethodImpl (MethodImplOptions.Synchronized)] public void KritickaSekce() {//...} Metoda Wait - uvolní zámek nad objektem, zablokuje se a umístí se do wait fronty monitoru Metody Pulse a PulseAll – upozorní vlákno (vlákna) ve frontě, že došlo ke změně stavu
Další třídy pro synchronizaci System.Threading.WaitHandle Metody WaitAny(), WaitAll(), WaitOne() Abstraktní třída System.Threading.Mutex Potomek třídy System.Threading.WaitHandle Ke sdílenému zdroji může přistupovat pouze to vlákno, kterému se podaří získat (acquire) instanci této třídy System.Threading.Interlocked Poskytuje metody na zvýšení a snížení hodnoty, cílem je, aby při změně integer hodnoty proběhlo její zvýšení nebo snížení jako jedna operace a jiné vlákno nemohlo v průběhu zvýšení nebo snížení přistoupit k proměnné. umožňuje tedy atomické operace s objekty Metody Increment(ref int), Decrement(ref int) Metoda CompareExchange(ref object, object, object) Metoda Exchange(ref object, object) System.Threading.AutoResetEvent, ManualResetEvent Potomek třídy EventWaitHandle (synchronizovaný Event) Umožňuje komunikaci mezi vlákny. Jedno vlákno čeká, dokud jiné vlákno nezavolá na stejné instanci této třídy metodu Set(). System.Threading.Semaphore Potomek třídy WaitHande Pro řízení přístupu více vláken ke zdrojům
Příklad – producent, konzument class Program { static void Main(string[] args) { Zasobnik zasobnik = new Zasobnik(VELIKOST_ZASOBNIKU); for (int i = 0; i < POCET_VLAKEN; i++) { Thread producent = new Thread(new ThreadStart(new Producent("Producent " + (i + 1), zasobnik).DoWork)); Thread konzument = new Thread(new ThreadStart(new Konzument("Konzument " + (i + 1), zasobnik).DoWork)); producent.Start(); konzument.Start(); } class Zasobnik { public void VlozHodnotu(int hodnota) { lock (this) { while (plny) { Monitor.Wait(this); } hodnoty.Add(hodnota); if (hodnoty.Count >= KAPACITA) { plny = true; } Monitor.PulseAll(this); } [MethodImpl(MethodImplOptions.Synchronized)] public int OdeberHodnotu() { while (hodnoty.Count == 0) { Monitor.Wait(this); } int hodnota = hodnoty[hodnoty.Count - 1]; hodnoty.RemoveAt(hodnoty.Count - 1); plny = false; Monitor.PulseAll(this); return hodnota; }
Synchronizace kolekcí v C# ArrayList ThreadSafe – pro některé případy – mnohonásobné čtení Metoda Synchonized, vrátí ThreadSafe ArrayList SortedList ThreadSafe – pro některé případy – mnohonásobné čtení Metoda Synchonized, vrátí ThreadSafe SortedList HashTable ThreadSafe – pro některé případy – mnohonásobné čtení a jedno přidávající vlákno Metoda Synchonized, vrátí ThreadSafe HashTable Stack Pro zajištění ThreadSafe užít metodu Synchronized Queue Pro zajištění ThreadSafe užít metodu Synchronized
Porovnání jazyků Java a C# v oblasti vláken JavaC# ZámekKlíčové slovo synchonized Užití v deklaraci nebo na část kódu Klíčové slovo lock Užití na část kódu Spouštění v samostatném vlákně Třída – potomek Thread nebo implementuje Runnable. Samostatně se provede metoda run() Třída Thread, delegát odkazuje na metodu, která má být v samostatném vlákně vykonána. wait, notify, notifyAll, sleep, join sleep – metoda Thread join – metoda Thread wait – metoda Object notify, notifyAll – metody Object V Javě tedy každá třída dědí metody wait, notify a notifyAll od předka java.lang.Object, které se používají pro operace s vlákny. Sleep – metoda Thread Join – metoda Thread Wait – metoda Monitor Pulse, PulseAll – metody Monitor V C# jsou ekvivalentními metodami Wait, Pulse a PulseAll třídy System.Threading.Monitor KolekceOddělené synchronizované a nesynchronizované kolekce Vždy záleží a konkrétní kolekci, zajištění synchronizace pomocí metody Synchronized Přístup do systému v rámci vláken neano
Shrnutí Pro práci s vlákny namespace System.Threading Hlavní třída reprezentující vlákno je Thread Pro zamykání procesů slouží třída Monitor Atomické operace zajišťuje třída Interlocked Přístup ke zdrojům zajišťuje Semaphore Existují kolekce se synchronizovaným přístupem Možnost řízení i na úrovni procesů OS
Za současným rozvojem jazyka C# stojí především vzrůstající obliba využívání frameworku.NET pro tvorbu podnikových aplikací.