HyperLink
Bejelentkezés
E-mail: 
Jelszó: 





Skip Navigation Links
 

Több szálon futó alkalmazás készítése


Példaprogram letöltése

7895 bájt

Amikor elindítunk alkalmazásunkon belül még egy - vagy esetleg több - szálat, valamilyen funkció végrehajtásának érdekében, akkor általában szükségünk lesz arra, hogy ezen feldolgozási folyamat aktuális állapotáról tájékoztassuk a felhasználót. Ehhez viszont szükségünk lesz arra, hogy az adott szál a Form-on lévő valamely kontrolt elérhesse és használhassa arra, hogy ezen keresztül megjelenítse az állapotát. Így például egy ProgressBar-t, vagy akár egy Label-t is felhasználhat a szál e célra. Mivel ezeket más szál is használhatja a programunkon belül, így ütközés fordulhat elő, mely nem kívánatos hibákat okozhat. Ennek elkerülése végett az adott szálban nem adhatunk egyszerűen értéket e kontrolok megfelelő property-jeinek.

A megvalósítandó feladat az lesz, hogy egy Label kontrolon fusson egy számláló, melynek aktuális értékét egy külön szálon növeljük. Amíg e számláló fut, programunk addig is képes további műveletek elvégzésére, hiszen Label Text property-jét egy külön szál kezeli, így a felhasználó nyugodtan dolgozhat tovább alkalmazásunkban.
Új szál létrehozásához szükségünk lesz a Thread osztály egy példányára, így készítsünk ehhez egy változót.
    private Thread th;
A számláló indítása előtt ellenőriznünk kell, hogy nem lett-e már létrehozva a szál.
    private void button1_Click(object sender, System.EventArgs e)
    {
      if (th != null)
      {
Ha a szál már létezik, akkor annak futását megszakítjuk.
        th.Interrupt();
        th = null;
      }
Most már biztonságosan létrehozhatunk egy új szálat, melyhez kell egy új Thread osztály. Ennek konstruktora egy ThreadStart osztály példányát várja, így ebből is létrehozunk egyet. A ThreadStart konstruktora egy olyan függvényt vár, mely az új szál fő funkciója lesz, vagyis ebben a függvényben van megadva a külön szálon futó kód.
      th = new Thread(new ThreadStart(ThreadFunction));
A szál létrehozása után az IsBackground property-n keresztül rendelkezhetünk arról, hogy a szál a háttérben fusson-e.
      th.IsBackground = true;
A Start függvényét meghívva pedig elindíthatjuk a szálat.
      th.Start();
    }
A szál létrehozásánál adtuk meg a ThreadFunction függvényünket, mely a Thread osztály Start függvényének hívásakor induló új szál kódját tartalmazza. Az új szál addig fut, amíg e függvény be nem fejezi a futását, vagy amíg az új szálat kívülről meg nem szakítják.
    public void ThreadFunction() 
    {    
      try
      {
Abban az esetben, ha egy szálon belül egy vizuális kontrolt szeretnénk elérni, mint jelen esetben is, akkor ezt csak úgy tehetjük meg, hogy MethodInvoker-t hívjuk segítségül, ennek konstruktorában megadjuk annak a függvénynek a nevét, mely elvégzi a Label szövegének frissítését.
        MethodInvoker mi = new MethodInvoker(UpdateLabel);
Mivel azt szeretnénk, hogy ez a szál addig fusson, ameddig a program, vagy amíg meg nem szakítják, így egy végtelen ciklust kezdeményezünk.
        while (true) 
        {
A ciklusmagon belül fogjuk aktivizálni az UpdateLabel függvényünket a BeginInvoke függvény hívással.
          BeginInvoke(mi);
          Thread.Sleep(50);
        }
      }
      catch
      {
      }
    }
A szál kódját célszerű mindig try - catch blokkba helyezni, mivel a szál külső megszakításakor (Interrupt függvény) mindig egy ThreadInterruptedException hiba keletkezik. Ha szükségünk van rá, akkor erre akár fel is készíthetjük a szál kódját az alábbi módon:
           catch (ThreadInterruptedException) 
           {
                ...
            }
Így a külön szálon futó kód is értesítést kaphat arról, hogy kívülről megszakították a futását és ilyenkor még elvégezheti a szükséges műveleteket mielőtt futása végleg leállna.
Az UpdateLabel függvénynek most már csak annyi a dolga, hogy növelje a számláló értékét eggyel.
    private void UpdateLabel()
    {
      label1.Text = (Convert.ToInt32(label1.Text) + 1).ToString();
    }
Ha a program futása közben szeretnénk leállítani az újonnan indított szálat, akkor ehhez az Interrupt függvényét kell meghívnunk. Előtte persze célszerű ellenőriznünk, hogy a szál objektuma valóban létrejött-e, különben leállítani sem tudjuk, de egy hibaüzenetet biztos kapunk, ha mégis megpróbáljuk.
    private void button2_Click(object sender, System.EventArgs e)
    {
      if (th != null)
      {
        th.Interrupt();
        th = null;
      }
    }
Fontos, hogy programunk bezárásakor, ha még van futó szál, melyet mi indítottunk az alkalmazásunkban, akkor azt leállítsuk. Ehhez a Form Dispose függvénye használható fel, mely akkor kerül meghívásra, mikor a programunk bezárása történik. Itt nincs más teendőnk, mint szintén az Interrupt segítségével leállítani a szálat, ha az még futna.
  protected override void Dispose( bool disposing )
  {
      if (th != null)
      {
        th.Interrupt();
        th = null;
      }

Könyv
Ez a cikk megtalálható ebben a könyvben: C# Software Offline 2002 évkönyv 517. 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 |