HyperLink
Bejelentkezés
E-mail: 
Jelszó: 





Skip Navigation Links
 

Szálak kezelése a Monitor osztállyal


Példaprogram letöltése

8377 bájt

Alkalmazás szálainak menedzselésére számtalan lehetőség kínálkozik a .NET Framework osztályainak segítségével. Cikkünkben a System.Threading névtér Monitor osztályát ismerhetjük meg részletesen, feltárva használatának lényegét, a metódusai közötti alapvető különbségeket.

Monitor osztály
A Monitor osztály alapvetően alkalmas arra, hogy biztosítsa a különböző objektumok elérésének szinkronizációját az alkalmazás egyes szálai között. A szál által végzett műveletben meghívva a Monitor osztály megfelelő metódusát elérhetjük, hogy az adott objektum egy bizonyos szálhoz tartozzon (LOCK), így az objektum más szálak részére nem lesz hozzáférhető.
Ez tulajdonképpen a kód egy bizonyos részletének blokkolását jelenti, mely így nem futtatható egy másik szál számára. A többi szál nem képes feloldani a zárat, ezt kizárólag a blokkoló szál teheti meg.
A blokkolás természetesen nem zárja ki azt, hogy egy másik szál egy másik objektumon hívja meg a blokkolt kódrészletet.
A Monitor osztály nem példányosítható. Metódusai statikusak, így erre nincs is szükség. A Monitor objektum által blokkolt kódrészletet kritikus szegmensnek is nevezi a szakirodalom.
A Monitor osztály alapvetően abban különbözik a WaitHandle osztály és az abból származó osztályok viselkedésétől, hogy a Monitor osztály teljesen menedzselt és hordozható, míg a WaitHandle és annak utód szinkronizációs osztályai a menedzselt és a nem-menedzselt objektumok közötti szinkronizációt valósítják meg, valamint segítségükkel igénybe vehetjük az operációs rendszer előnyös jellemzőit.
Vizsgáljuk meg a metódusok jellemzőit.
Enter
Osztály: Monitor
public static void Enter(
object obj
);
Létrehoz egy kizárólagos LOCK-ot a paraméterül átadott objektumon. Ez – ahogy majd a gyakorlati példában is látható lesz – azt jelenti, hogy amennyiben egy másik objektum is meghívja az Enter metódust, de a blokkoló objektum nem futtatta az Exit metódust, akkor a második szál várakozni kényszerül addig, míg az első nem szabadítja fel az objektumot. Ez lehetőséget ad a szálak manuális, vagy feltételhez kötött menedzselésére.
Az Enter metódus jellemzője, hogy amennyiben egy érték típust adunk át paraméterként, akkor az Object típusként tárolódik (boxing). Így, ha a metódust újra meghívjuk ugyanazzal az értékkel, akkor az egy másik Object típusban tárolódik, így a LOCK művelet nem történik meg.
Amennyiben az Enter metódusban megadott objektumtól eltérő objektummal hívjuk meg az Exit metódust, akkor egy System.SynchronizationLockException kivétel keletkezik.
Az Enter metódus tehát egy szál számára kizárólagos jogokat biztosít egy objektumon a többi szállal szemben.
Paraméterek
object obj
A blokkolt objektum.
Exit
Osztály: Monitor
public static void Exit(
object obj
);
Feloldja az Enter metódus által egy objektumon létrehozott blokkolást, vagyis a többi várakozó szál – ha van ilyen - számára is elérhetővé teszi az objektumot, illetve a kódrészletet.
Paraméterek
object obj
A felszabadított objektum, amely meg kell, hogy egyezzen az Enter metódusban megadott objektummal.
Az Enter-Exit metódus-pár a lock kulcsszóval is helyettesíthető, annak paramétereként megadva az objektumot.
Object obj = ”...”;
...
lock(obj)
{
  ...	
}
A következőkben a TryEnter metódust mutatjuk be. A metódusnak több változata van, a legjellemzőbb deklarációja a következő.
TryEnter
Osztály: Monitor
public static bool TryEnter(
object obj,
int millisecondsTimeout
);
A metódussal megpróbálhatja egy másik szál elérni a blokkolt objektumot, azonban ez nem biztos, hogy sikeres. Mindenesetre jelzi, hogy szándékában áll az objektumot használni.
Paraméterek
object obj
Egy másik szál által blokkolt objektum, melynek hívását a metódus kezdeményezi.
int millisecondsTimeout
Megadható, hogy hány milliszekundum ideig várakozik a második szál az objektum felszabadulására. Amennyiben az időperiódus alatt az objektum nem szabadul fel, akkor a metódus visszatérési értéke FALSE.
Visszatérési érték
Logikai érték, mely jelzi, hogy a hívni kívánt objektum elérhető-e, vagy sem.
Amennyiben a TryEnter metódus azon változatát hívjuk meg, melyben nem adunk meg időperiódust, akkor a metódus a sikertelen hívás után rögtön visszatér.
Pulse
Osztály: Monitor
public static void Pulse(
object obj
);
A sorban következő szál számára jelezhetjük, hogy az objektum állapotában változás következett be. Ekkor a sorban következő szál KÉSZ állapotba kerül, minek következtében az objektum felszabadulásakor kezd el futni.
A szinkronizált objektum számtalan referenciával rendelkezik: ide tartozik annak a szálnak a referenciája, amely éppen blokkolja, amely a KÉSZ sorban várakozik a futásra, vagy azok, melyek várakoznak, de nem kaptak értesítést.
A Pulse és a Wait (felszabadító) metódusokat a lock utasításon belül kell meghívni.
Paraméterek
object obj
A blokkot objektum.
PulseAll
Osztály: Monitor
public static void PulseAll(
object obj
);
A összes várakozó szálat értesíthetjük az objektum felszabadításáról.
Paraméterek
object obj
A blokkolt objektum.
Wait
Osztály: Monitor
public static bool Wait(
object obj
);
Felszabadítja a blokkolt objektumot, viszont a szálat is blokkolja addig, míg a szál nem hoz létre ismét egy kizárólagos foglalást az objektumon.
Paraméterek
object obj
A blokkolt objektum.
Visszatérési érték
Amennyiben az objektumot ismét lefoglalja a szál, akkor a visszatérési érték TRUE, ellenkező esetben a metódus nem tér vissza.
Gyakorlati példa
A példánkban három szálat indíthatunk el Start gombbal. Az első szál lefoglalja a ProgressBar objektumot, így a másik két szál nem képes futtatni a DoProcess metódust, melyben használjuk az adott objektumot.
A szálakat a hagyományos manuális eljárással indítjuk. Létrehozzuk a szálpéldányokat.
Thread th1 = new Thread(new ThreadStart(DoStart1));
Thread th2 = new Thread(new ThreadStart(DoStart2));
Thread th3  = new Thread(new ThreadStart(DoStart3));
Majd a Start metódusokat meghívva elindítjuk őket.
th1.Start();
th2.Start();
th3.Start();
Az első szál kétféleképpen üzemelhet: lefoglalja az objektumot az Enter metódussal, és a többi szál várakozni kényszerül, míg az objektum felszabadul. Ekkor az Enter metódust hívjuk.
Monitor.Enter(progressBar1);
Amennyiben a jelölőnégyzetet bejelöljük, vagyis azt szeretnénk, hogy a szál csak induljon el, akkor a PulseAll metódust hívjuk meg.
Monitor.Pulse(progressBar1);
Az első metódus hívása után kezd el futni a DoProcess metódus.
DoPrecess(progressBar1,1);
Ezután az objektumot felszabadítjuk.
Monitor.Exit(progressBar1);
A második szál a TryEnter metódussal tesz kísérletet a futtatásra, de mivel nem adtunk megy türelmi időt, így műveletvégzés nélkül kilép.
Monitor.TryEnter(progressBar1)
...
Itt már az Exit metódus nem kerül meghívásra.
Amennyiben az első szál csak elkezd futni, a rendszer a második szálat kezdi futtatni.
A harmadik szál esetén kétfajta állapot lehetséges: vagy várakozik, és akkor a TryEnter metódust egy, az első szál műveleti idejénél (10 másodperc) nagyobb periódusidővel hívjuk meg. Ekkor a szál lefut vagy az első után, vagy a második után (amikor az elsőt csak elindítjuk).
waittime = 12000;
...
Monitor.TryEnter(progressBar1,waittime)
...
A második esetben csak 2 másodpercet vár, ez azonban letelik, mielőtt a második befejezné a futást. Ekkor a harmadik szál futás nélkül kilép.

Könyv
Ez a cikk megtalálható ebben a könyvben: C# Software Offline 2003 évkönyv 499. oldal

Felhasználási feltételek
A Software Online szoftverfejlesztői magazin mindegyik cikke, minden megjelent képe, és egyéb publikált anyaga szerzői jog védelme alatt áll! Bármilyen formában történő másodlagos terjesztésük, közzétételük vagy felhasználásuk kizárólag a kiadó előzetes írásbeli engedélyével történhet!

Copyright © 1999-2012 Animare Software Kft. Minden jog fenntartva!
| Készült: Animare Stúdió | Adatvédelem | Kapcsolat |