A Thread osztály tagjai
Az alkalmazások szálait reprezentáló Thread osztály lehetőségeit számba véve látható, hogy az osztály számtalan property-vel rendelkezik, amelyek lekérdezésével jól körülhatárolható képet kaphatunk az adott szálról. A függvények könnyen használhatók, legtöbbjük paraméter nélkül hívható meg egy adott szálra, mely nagyon megkönnyíti a szálakkal való munkát.
A cikk első felében bemutatjuk az osztály tagjait, majd a mellékelt alkalmazásban megvizsgáljuk felhasználásukat.
Az osztály property-jei a következők:

ApartmentState
Osztály: Thread
public ApartmentState ApartmentState {get; set;}
Megadja az adott szál ’apartment-állapotát’.
Az ’apartment’ egy logikai konténer a process területén belül. Az adott apartment-en belül minden objektum fogadhat hívást az apartment minden szálától. A property beállításával adhatjuk meg a CLR-nek, hogy ún. menedzselt szálak esetén milyen apartment kerüljön létrehozásra. Három lehetséges értéke van:
| Értékek |
Jelentés |
| STA (Singlethreaded Apartment) |
A szál egy szálat engedélyező apartment-et hoz létre és inicializál. |
| MTA (Multithreaded Apartment) |
A szál több szálat engedélyező apartment-et hoz létre és inicializál. |
| Unknown |
Az ApartmentState property nincs beállítva. |
A property értéke csak akkor állítható be, amikor a szál Running vagy Unstarted állapotban van; egyszer állatható be futás során.

CurrentContext
Osztály: Thread
public static Context CurrentContext {get;}
Megadja az adott Context objektumot, amelyben a szál fut.

CurrentCulture
Osztály: Thread
public CultureInfo CurrentCulture {get; set;}
Megadja az adott szál kulturális beállításait.

CurrentPrincipal
Osztály: Thread
public static IPrincipal CurrentPrincipal {get; set;}
Megadja, hogy milyen szabály-alapú biztonsági beállítások vannak érvényben az adott szálra, vagyis közvetve azt, hogy melyik felhasználó jelentkezett be a számítógépen.
Ennek a property-nek az értelmezéséhez pár szót ejtenünk kell a .NET biztonsági lehetőségeiről. A közös nyelvi futtató rendszer és a .NET Framework számtalan osztályt és szolgáltatást biztosít annak érdekében, hogy a fejlesztők biztonságos kódot írjanak. Az osztályok és szolgáltatások lehetővé teszik, hogy az ezekkel írt kódoknak a rendszeradminisztrátorok testre szabhassák hozzáférésüket védett erőforrásokhoz. A kódhozzáférés szabályozására több módszer is rendelkezésre áll, ezek közül az ún. kulcs és a szerep-alapú biztonsági rendszerrel van összefüggésben a property-ben megadandó érték.
A szerep-alapú biztonsági rendszer esetén az ún. elöljáró (’principal’) reprezentálja az azonosítóját és szerepét az adott felhasználónak, valamint a szerephez kapcsolt viselkedést. Az említett biztonsági rendszer háromféle elöljárót támogat:
| Elöljáró |
Jelentés |
| Általános elöljáró |
Azok a felhasználók és szerepek, melyek a Windows NT és Windows 2000 felhasználóktól és szerepektől függetlenül léteznek. |
| Windows elöljáró |
Reprezentálja a Windows rendszer felhasználóit és azok szerepeit. |
| Alkalmazás-specifikus elöljáró |
Alkalmazásban megadható elöljáró, mely az alapvető szerepek kiterjesztése. |
A menedzselt kód a Principal osztályon keresztül érheti el az elöljáró azonosítóját és a kapcsolódó szerepet. Az azonosítót egy Identity típusú hivatkozáson keresztül érheti el.
A hálózatok többségében egy felhasználói azonosító reprezentálja a felhasználókat és programokat, míg a csoport azonosító a felhasználói csoportokat és ezek jogait. Az elöljárók a .NET rendszerben egységbe zárják az azonosítókat és szerepeket.
A mellékelt alkalmazásban egy, az IPrincipal interfészt implementáló WindowsPrincipal nevű osztály segítségével érjük el az adott elöljárót.

CurrentThread
Osztály: Thread
public static Thread CurrentThread {get;}
Visszaad egy hivatkozást az aktuálisan futó szálra.

IsAlive
Osztály: Thread
public bool IsAlive {get;}
Visszaadja, hogy az adott szál él-e. True érték esetén az adott szál elindított állapotban van, False esetén nem.

IsBackground
Osztály: Thread
public bool IsBackground {get; set;}
Megadható, hogy az adott szál a háttérben fusson-e, vagy nem. True értéket adva a property-nek a szál háttérben futó szál lesz.

Name
Osztály: Thread
public string Name {get; set;}
Beállítható egy tetszőleges név a szálhoz.

Priority
Osztály: Thread
public ThreadPriority Priority {get; set;}
Prioritás rendelhető az adott szálhoz. Értékének beállításához egy ThreadPriority enumerátor értékeit használhatjuk fel. A szálak prioritását egész számok reprezentálják, melyek meghatározzák a szálak ütemezését abban az esetben, amikor azonos erőforráson végeznek műveletet egy időben. A szálak prioritását az operációs rendszer dinamikusan is képes állítani attól függően, hogy mely munkafolyamat aktív. Értékei a következők:
| Értékei |
Meghatározás |
| AboveNormal |
Magasabb, mint a Normál prioritás. |
| BelowNormal |
Alacsonyabb, mint a Normál prioritás. |
| Highest |
Legmagasabb prioritás. |
| Lowest |
Legalacsonyabb prioritás. |
| Normal |
Normál prioritás. |
Alapértelmezett értéke a Normal.

ThreadState
Osztály: Thread
public ThreadState ThreadState {get;}
Megadja, hogy az adott szál a létrehozásától a megszüntetéséig terjedő időintervallumban éppen milyen futási állapotban van. A szálak létrehozásukkor az Unstarted állapotban vannak. Néhány lehetséges értéke a következő:
| Érték |
Meghatározás |
| Running |
A szál fut. |
| Unstarted |
A szál elindult |
| Suspended |
A szálra az alkalmazásban meghívódott a Suspend metódus. |
| SuspendRequested |
Folyamatban van a felfüggesztés. |
| WaitSleepJoin |
A szálra az alkalmazásban meghívódott a Wait, Join vagy Sleep metódus. |
| Background |
A szál a háttérben fut. |
| AbortRequested |
Folyamatban van a megszüntetés. |
| Stopped |
A szál leállított állapotban van. |
A property-k után lássuk, milyen metódusai vannak az osztálynak:

Abort
Osztály: Thread
public void Abort(
);
Előidéz egy speciális, ThreadAbortException nevű kivételt, mely nem elkapható. A try – finally blokk valamennyi finally elemében megvalósított kód lefut, mielőtt a szál abortál, mivel ez nem jár a szál azonnali megszűnésével. A teljes megszüntetéshez meg kell hívni a szálra a Join metódust.
Abban az esetben, ha a szálra meghívjuk az Abort metódust, de az nincs elindítva, akkor elinduláskor fog abortálni.

AllocateDataSlot
Osztály: Thread
public static LocalDataStoreSlot AllocateDataSlot(
);
Segítségével lefoglalhatunk a process memóriaterületén belül egy területet a szálaknak. A lefoglalt területre névvel nem hivatkozhatunk.
Visszatérési érték
A lefoglalt területet egy LocalDataStoreSlote típusú objektum reprezentálja, mintegy egységként kezelve azt. A memóriaterület azon része, melyet a szálak szál-specifikus adatok tárolására használhatnak fel. A CLR egy multi-slot memóriatömböt hoz létre minden egyes process számára, melyet elindít. A szálak metódusaikkal lefoglalnak területet a tömbben, adatokat tesznek bele, illetve olvasnak ki, majd felszabadítják azt.

AllocateNamedDataSlot
Osztály: Thread
public static LocalDataStoreSlot AllocateNamedDataSlot(
string name
);
Segítségével lefoglalhatunk a process memóriaterületén belül egy területet a szálaknak. A lefoglalt területre névvel hivatkozhatunk.
Paraméterek
string name
Az adatterület neve, mellyel rá hivatkozhatunk.
Visszatérési érték
Azonos az AllocateDataSlot metódusnál említettel.

FreeNamedDataSlot
Osztály: Thread
public static void FreeNamedDataSlot(
string name
);
Segítségével fel tudjuk szabadítani a névvel rendelkező memóriaterületeket a process memóriaterületén belül. A lefoglalt területre névvel hivatkozhatunk.
Paraméterek
string name
Az adatterület neve, mellyel rá hivatkozhatunk.

GetData
Osztály: Thread
public static object GetData(
LocalDataStoreSlot slot
);
A szálak által a tárolóterületen elhelyezett adatok visszanyerését teszi lehetővé.
Paraméterek
LocalDataStoreSlot slot
A lefoglalt memóriaterület objektuma.
Visszatérési érték
A kinyert adatot reprezentáló objektum.

GetDomain
Osztály: Thread
public static AppDomain GetDomain(
);
Megadja, hogy az adott szál milyen alkalmazás futási környezetébe tartozik.
Visszatérési érték
Egy AppDomain típusú objektum, mely információval szolgál a szálat futtató alkalmazásról.

GetDomainID
Osztály: Thread
public static int GetDomainID(
);
Megadja, hogy mi az adott szál domain azonosítója.
Visszatérési érték
Egész szám, mely a domain-t azonosítja.

GetNamedDataSlot
Osztály: Thread
public static LocalDataStoreSlot GetNamedDataSlot(
string name
);
Visszaad egy hivatkozást a paraméterben megadott nevű memóriaterületre, melyet lefoglaltunk.
Paraméterek
string name
Az adatterület neve, mellyel rá hivatkozhatunk.
Visszatérési érték
A lefoglalt memóriaterület objektuma.

Interrupt
Osztály: Thread
public void Interrupt(
);
Megszakít egy WaitSleepJoin állapotban levő szálat.

Join
Osztály: Thread
public void Join(
);
A hívó szál egy másik szálra várhat ezzel a metódussal. Addig vár, amíg az adott szál megszűnik. A metódus másik két implementációjában egy időtartamot azonosító egész számot, vagy egy időbélyeget adhatunk meg, amelyek meghatározzák a szál várakozási idejét.

ResetAbort
Osztály: Thread
public static void ResetAbort(
);
Törli az adott szálra kiadott Abort kérést. A kódnak ControlThread joggal kell rendelkeznie. Ez egy SecurityPermission enumerátor értékének megválasztásával történik.

Resume
Osztály: Thread
public void Resume(
);
A felfüggesztett szálat újra elindítja (folytatás).

SetData
Osztály: Thread
public static void SetData(
LocalDataStoreSlot slot,
object data
);
Adat helyezhető a memóriaterületre.
Paraméterek
LocalDataStoreSlot slot
A lefoglalt memóriaterület objektuma.
object data
A tárolandó adat objektuma.

Sleep
Osztály: Thread
public static void Sleep(
int millisecondsTimeout
);
Adott időre a szál felfüggeszthető.
Paraméterek
int millisecondsTimeout
Az időintervallum.

Start
Osztály: Thread
public void Start(
);
Elindítja az adott szálat, vagyis a létrehozáskor a konstruktorban megadott függvényt futtatja.

Suspend
Osztály: Thread
public void Suspend(
);
Felfüggeszti az adott szálat. A felfüggesztett szálra nincs hatással.
Gyakorlati felhasználás
A mellékelt programban a Form-on található TabControl füleire kattintva érhető el a két funkció-csoport. A ’Műveletek’ fülre kattintva három gomb látható, melyekkel elindítható (Indítás), felfüggeszthető (Szünet), valamint megszüntethető (Vége) az alkalmazásban használt két szál.
A program indításakor egy DataTable tárolót feltöltünk adatokkal. A ’th’ szál, melynek neve ’Adatszál’, folyamatosan rekordokat szúr be ebbe a DataTable tárolóba. A szálak létrehozása a hagyományos módon történik:
private void tButton_Click(object sender, System.EventArgs e)
{
th = new Thread(new ThreadStart(this.ThreadFunction));
th1 = new Thread(new ThreadStart(this.ThreadFunction1));
th.IsBackground = true;
th1.IsBackground = false;
th.Name = "Adatszál";
th1.Name = "Cimkeszál";
th.Start();
th1.Start();
A következő lépésben egy FillList metódus feltölti az ’Adatszál’ adataival a TabControl ’Adatszál tulajdonságai’ fül alatt megtalálható ListBox kontrolt.
A gombok alatti listában pedig elhelyezzük a szálak állapotinformációit, melyet minden gombnyomásra frissítünk, tükrözve a helyes állapotot.
Az ’Adatszál’ elhelyezi a frissített adathalmazt a LocalDataStoreSlot objektumba:
lSlot = Thread.AllocateNamedDataSlot("data");
DataTable dtHelp = new DataTable();
dtHelp = dt.Copy();
Thread.SetData(lSlot,dtHelp);
...
}
A szálak indításakor megadott függvények neve ThreadFunction és ThreadFunction1, az elvégzett feladatokat a következő metódusokban valósítottuk meg: Adatszál esetén UpdateData, Cimkeszál esetén RowCount a neve a metódusnak.
A Szünet gomb megnyomásakor a th szálra meghívunk egy Suspend metódust, majd indításához a Resume eljárást. A th1 szálat nem blokkoltuk, azonban állapotára hatással van a másik szál állapota, mivel azonos tárolót használnak.
private void pauseButton_Click(object sender, System.EventArgs e)
{
if (threadState == 1)
{
dieButton.Enabled = false;
pauseButton.Text = "Folytatás";
th.Suspend();
threadState = 0;
GetThreadStates(th,th1);
}
else
{
dieButton.Enabled = true;
pauseButton.Text = "Szünet";
th.Resume();
threadState = 1;
GetThreadStates(th,th1);
}
}
A Vége gombbal mindkét szálat megszüntetjük az Abort, majd a Join metódusok meghívásával. A művelet végén felszabadítjuk a memóriaterületet is. A szálak aktuális állapota a ListBox kontrolban, a teljes adathalmaz pedig a DataGrid kontrolban látható.
private void dieButton_Click(object sender, System.EventArgs e)
{
if (th != null && th1 != null)
{
dt.Clear();
dt = (DataTable)Thread.GetData(lSlot);
grid.DataSource = dt.DefaultView;
th.Abort();
th1.Abort();
th.Join();
th1.Join();
GetThreadStates(th,th1);
th1 = null;
th = null;
}
Thread.FreeNamedDataSlot("data");
startButton.Enabled = true;
pauseButton.Enabled = dieButton.Enabled = false;
}