Halad Programozs Szlkezels szinkronizci V 1 0 OENIK

  • Slides: 16
Download presentation
Haladó Programozás Szálkezelés + szinkronizáció V 1. 0 OE-NIK HP 1

Haladó Programozás Szálkezelés + szinkronizáció V 1. 0 OE-NIK HP 1

Többszálú programok főbb lehetséges problémái • Versenyhelyzet („race condition”) – A párhuzamosan futó szálak

Többszálú programok főbb lehetséges problémái • Versenyhelyzet („race condition”) – A párhuzamosan futó szálak kommunikációjához szinte biztosan szükség van közös erőforrások (memória (közös változók), portok, I/O eszközök, fájlok) használatára – Ha ezek állapotát egy szál módosítja, de közben más szálak is hozzájuk férnek, akkor az utóbbi szálak könnyen hibás vagy félkész adatokhoz juthatnak • Holtpont („deadlock”) – A szál olyan erőforrásra várakozik, ami sohasem érkezik meg – Két vagy több szál egymásra várakozik (így egyik sem fejeződik be soha) V 1. 0 OE-NIK HP 2

Versenyhelyzet demó • Készítsünk olyan programot, amiben több szál egy közös eredményt számol. (Pl:

Versenyhelyzet demó • Készítsünk olyan programot, amiben több szál egy közös eredményt számol. (Pl: „együtt” elszámolnak 100000 -ig + Thread. Sleep-ek. ) • Készítsünk olyan konzolos programot, amiben több szál egy-egy saját eredményt számol, és az eredmény %-os állapotát saját színnel %-onként kiírják a konzolba V 1. 0 OE-NIK HP 3

Versenyhelyzet példák Szál 1 Szál 2 Eredeti kód t=x x=t+1 u=x x=u+2 1. lehetséges

Versenyhelyzet példák Szál 1 Szál 2 Eredeti kód t=x x=t+1 u=x x=u+2 1. lehetséges kimenetel (x értéke 0) t=x x = t + 1 (x értéke 1) 2. lehetséges kimenetel (x értéke 0) u=x t=x x=t+1 3. lehetséges kimenetel V 1. 0 u=x x = u + 2 (x értéke 2) (x értéke 0) t=x x = t + 1 (x értéke 1) OE-NIK HP u=x x = u + 2 (x értéke 3) 4

Versenyhelyzet • Sok nyelvi konstrukció használatából is adódhat versenyhelyzethez vezető állapot! • X++ –

Versenyhelyzet • Sok nyelvi konstrukció használatából is adódhat versenyhelyzethez vezető állapot! • X++ – A ++ az utasítások szintjén különálló olvasás és írás műveletből áll. (Memóriából kiolvasásig jut el „A” szál, amikor jön „B” szál és pl. elvégzi az X növelését. „A” szál számára azonban az X még a memóriából kiolvasott értéket viseli) • X += 2 – A += az utasítások szintjén különálló olvasás és írás műveletből áll. Mint előbb. • A[i] += 1 – Előfordulhat, hogy másik szál épp ugyanezen indexre dolgozna (esetleg más néven). Mint előbb. • Természetesen magas szinten is létezik a probléma if (!list. Contains(key)) list. Add(key); Másik szál a két hívás lefutása között beillesztheti ugyanezt a kulcsot A példák forrása: http: //www. drdobbs. com/tools/avoiding-classic-threading-problems/231000499 V 1. 0 OE-NIK HP 5

Holtpont demó • Készítsünk olyan WPF-es programot, amely hosszú műveleten dolgozik, és az állapotát

Holtpont demó • Készítsünk olyan WPF-es programot, amely hosszú műveleten dolgozik, és az állapotát (eredmény kiszámolásának %-os állását) kiírja egy progressbar-ra • Legyen egy gomb, amit megnyomva Wait-eljünk rá az eredményt számoló taszkra, és ha az véget ért, írjunk ki valamit (pl: „az eredmény elkészült”) • Nem adatkötéssel csináljuk – Adatkötés esetén ugyanígy fellép a bemutatni kívánt probléma, csak a kiváltó okok nem láthatók V 1. 0 OE-NIK HP 6

Holtpont • Oka (példából): – Szál 1: hosszú műveletet végez, és néha Invoke()-ol, hogy

Holtpont • Oka (példából): – Szál 1: hosszú műveletet végez, és néha Invoke()-ol, hogy kiírja az aktuális állapotát. – Főszál: a futás egy bizonyos pontján Join()/Wait()-val megpróbálja bevárni Szál 1 -et. – Következmény: Szál 1 éppen az Invoke()-ban van, tehát főszálra vár, amikor a főszál pedig a Join()/Wait() miatt éppen Szál 1 -re vár. • Klasszikus holtpont példa (kritikus szakasszal; magyarázat később): – Erőforrásokat lockkal próbáltunk védeni. Mindkét szál már belépett az első kritikus szakaszba, ott viszont várakoznia kell, hogy hozzájusson a másik lehetséges erőforráshoz. V 1. 0 1 lock (a) 2 { // feldolgozás 3 lock (b) 4 { 5 // feldolgozás 6 } 7 8 } 1. szál 1 lock (b) 2 { // feldolgozás 3 lock (a) 4 { 5 // feldolgozás 6 } 7 OE-NIK HP 8 } 2. szál 7

Versenyhelyzet és holtpont kivédése • Versenyhelyzet akkor áll fenn, amikor több szál próbál egyszerre

Versenyhelyzet és holtpont kivédése • Versenyhelyzet akkor áll fenn, amikor több szál próbál egyszerre azonos adathoz hozzáférni – Ha megoldható, ne használjunk a szálak számára közös objektumokat (referenciatípusok esetén különösen figyelni!) – Bizonyos feladatok/adatok esetén értéktípusok megfontolandók lehetnek – Ha ez nem megoldható, akkor szálszinkronizáció – De: OK a szálak számára közös adat, HA az elérés minden szál részéről readonly • A holtpont kivédésére nincs megoldás (alapos tervezés!) V 1. 0 OE-NIK HP 8

Szinkronizáció • A szálszinkronizáció biztosítja, hogy párhuzamosan egymás mellett futó szálak nem azonos időben

Szinkronizáció • A szálszinkronizáció biztosítja, hogy párhuzamosan egymás mellett futó szálak nem azonos időben hajtanak végre egy adott programszakaszt • Több formája van (kölcsönös kizárás, randevú) • Sok programozói munkát igényel, extrém módon hibaérzékeny, rosszul tesztelhető – Nem minden hiba jön elő minden esetben, minden konfiguráció mellett… • Lassít – Rossz tervezéssel gyakorlatilag sorossá redukálható a végrehajtás • Ha lehet, próbáljuk elkerülni (külön adat a szálaknak stb. ) – Sokszor nem lehet V 1. 0 OE-NIK HP 9

Szinkronizáció kölcsönös kizárással • Kritikus szakasz („critical section”) A programokon belül megjelölt kritikus kódrészletek

Szinkronizáció kölcsönös kizárással • Kritikus szakasz („critical section”) A programokon belül megjelölt kritikus kódrészletek soros végrehajtását biztosítja több párhuzamos szál esetén is. Amíg az egyik szál az „A” kritikus szakaszon dolgozik, a többi szál nem léphet be az „A” kritikus szakaszba. . NET osztályok: System. Threading. Monitor (és a C# „lock” utasítása), System. Threading. Mutex, System. Threading. Reader. Writer. Lock stb. • Szemafor („semaphore”) A kritikus szakasz általánosítása (többpéldányos erőforrások esetén egyszerre több szál belépését is lehetővé teszi). . NET osztály: System. Threading. Semaphore • Atomi végrehajtás („interlocked execution”) Egyes egyszerű műveletek oszthatatlan végrehajtását biztosítja (igen gyors). . NET osztály: System. Threading. Interlocked • Csővezeték („pipe”), konkurrens gyűjtemények V 1. 0 Olvasható és írható tároló, amely szükség szerint várakoztatja az igénylőket. (Az ún. „termelő-fogyasztó” probléma megoldására készült. ) 10. NET-ben: System. Collections. Concurrent osztályai

Szinkronizáció bevárással (randevú) • Esemény („event”) Lehetőséget ad alkalmankénti vagy rendszeres jelzésre (pl: szál

Szinkronizáció bevárással (randevú) • Esemény („event”) Lehetőséget ad alkalmankénti vagy rendszeres jelzésre (pl: szál jelzi, hogy végzett a feladatával). . NET osztályok: System. Threading. Auto. Reset. Event, System. Threading. Manual. Reset. Event stb. • Időzítő („timer”) Relatív vagy abszolút időhöz való igazodást tesz lehetővé. . NET osztályok: System. Windows. Forms. Timer, System. Timers. Timer, System. Threading. Timer stb. V 1. 0 OE-NIK HP 11

Példa szinkronizációra (a „lock” utasítás) 1 2 3 4 5 6 7 8 9

Példa szinkronizációra (a „lock” utasítás) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 V 1. 0 using System; using System. Threading; Figyelem: SOHA ne írjunk le az alábbiakra hasonlító kódot: class Program { private static int counter = 0; private static object lock. Object = new Object(); static void Main(string[] args) { Thread t 1 = new Thread(Thread. Method); t 1. Start(); Thread t 2 = new Thread(Thread. Method); t 2. Start(); } } lock (this) vagy lock (typeof(Program)) azaz sose lockoljunk olyat, amiről nem tudjuk befolyásolni, ki fér hozzá A lock utasítás nélkül a metódus sorosan (egy szálon futtatva) helyesen működik, párhuzamosan (több szálon) azonban nem private static void Thread. Method() { lock (lock. Object) { counter++; Thread. Sleep(500); Console. Write. Line("A számláló állása: " + counter); } } OE-NIK HP 12

Feladat • A és B barátságos számok, ha osztóösszegük kölcsönösen egyenlő a másik számmal

Feladat • A és B barátságos számok, ha osztóösszegük kölcsönösen egyenlő a másik számmal • Vagyis: „A” osztóösszege (önmagát kihagyva) B „B” osztóösszege (önmagát kihagyva) A • Feladat: írjuk ki az összes barátságos számot 1 000 -ig a lehető leggyorsabban • Osztóösszegek meghatározása: – Szokványos módszerrel: Ciklus i=2 -től Gyök(X)-ig, minden osztót és osztópárt hozzáadok az összeghez sok osztás – Eratosthenes szita: a 2 -t mint osztót hozzá kell adni az osztóösszeghez a következő számoknál: 4, 6, 8, … A 3 -t mint osztót a 6, 9, 12 számoknál … etc V 1. 0 OE-NIK HP 13

Feladat Készítsünk többszálú konzolos alkalmazást, amely során két szál használja ugyanazt az erőforrást, amit

Feladat Készítsünk többszálú konzolos alkalmazást, amely során két szál használja ugyanazt az erőforrást, amit esetünkben egy számokat tároló sor jelképez. Az egyik szál feladata a sor feltöltése, a másik feladata a sorból egy elem feldolgozása (kivétele). A fejlesztés közben gondoskodjunk a szálak szinkronizációjáról is! Ötletek: – Először egyszerű megvalósítással döntsük el, szükség van-e szinkronizációra, majd ha úgy ítéljük meg, hogy igen, akkor használjuk a lock utasítást vagy a Monitor osztály statikus Enter(), illetve és Exit() metódusát – Szinkronizáció esetén a jobb teljesítmény érdekében igyekezzünk a lehető legrövidebbre venni a kritikus szakaszt V 1. 0 OE-NIK HP 14

Megoldás V 1. 0 OE-NIK HP 15

Megoldás V 1. 0 OE-NIK HP 15

Irodalomjegyzék • J. Richter: CLR via C#, Fourth Edition Kiadó: Microsoft Press, 2012 Web:

Irodalomjegyzék • J. Richter: CLR via C#, Fourth Edition Kiadó: Microsoft Press, 2012 Web: http: //www. wintellect. com/ Nyelv: angol További források: MSDN, Miklós Árpád prezentációi V 1. 0 OE-NIK HP 16