HIK Elektronikus Felsőoktatási Tankönyv- és Szakkönyvtár
A Kempelen Farkas Felsőoktatási Digitális Tankönyvtár/vagy más megjelenítő által közvetített digitális tartalmat a felhasználó a szerzői jogról szóló 1999. évi LXXVI. tv. 33. paragrafus (4) bekezdésében meghatározott oktatási, illetve tudományos kutatási célra használhatja fel. A felhasználó a digitális tartalmat képernyőn megjelenítheti, letöltheti, arról elektronikus adathordozóra vagy papíralapon másolatot készíthet, adatrögzítő rendszerében tárolhatja. A Kempelen Farkas Felsőoktatási Digitális Tankönyvtár/vagy más megjelenítő weblapján található digitális tartalmak üzletszerû felhasználása tilos, valamint kizárt a digitális tartalom módosítása és átdolgozása, illetve az ilyen módon keletkezett származékos anyag további felhasználása.

16.39. Többszálú programozás

A többszálú programozás viszonylag új technika, segítségével lehetőség nyílik a processzor hatékonyabb kihasználására, több processzoros rendszerek programozására. A több szálat használó alkalmazások fejlesztésének lehetősége nem a .NET újítása, de hatékony támogatást ad azok készítéséhez.

A párhuzamos, vagy többszálú programok fogalma megtévesztő lehet. Egy processzor esetén nem fejezik be futásukat hamarabb, és a szálak külön – külön sem futnak rövidebb ideig, viszont több processzor esetén a futási idő radikálisan csökkenhet.

Egy processzoros rendszerekben is előnyt jelenthet a többszálú programok írása, futtatása. Előfordulhat, hogy több program, vagy egy program több szála fut egy időben, s mialatt az egyik szál adatokra vár, vagy éppen egy lassabb perifériával, eszközzel kommunikál, a többi szál használhatja az értékes processzoridőt. Természetesen az egyes szálakat valamilyen algoritmus ütemezi, s azok szeletei egymás után futnak és nem egy időben.

A .NET rendszerben akkor is szálkezelést valósítunk meg, amikor egyszerű programokat írunk. A futó alkalmazásunk is egy programszál, ami egymagában fut, használja a különböző erőforrásokat és verseng a processzoridőért.

Amennyiben tudatosan hozunk létre többszálú programokat gondoskodni kell arról, hogy a szálkezelő elindítsa és vezérelje a szálakat. A .NET a szálkezelőnek átadott szálakat ütemezi, és megpróbálja a számukat is optimalizálni, nagyban segítve ezzel a programozó dolgát. A szálakat természetesen magunk is elindíthatjuk, még a számukat is megadhatjuk, de mindenképpen jobb ezt a rendszerre bízni.

(Az következőekben ismertetett programhoz a Microsoft által kiadott ”David S Platt: Bemutatkozik a Microsoft .NET” című könyvben publikált Párhuzamos Kódokat bemutató fejezetéből vettük az alapötletet, majd ezt fejlesztettük tovább és írtuk át C# nyelvre, mert talán így tudjuk a legegyszerűbben bemutatni a több szálú programokat. Az említett könyv olvasása javasolt annak, aki a .NET rendszer használatát és finomságait teljes mértékben meg akarja ismerni!)

A példaprogram egy listView komponens segítségével bemutatja, hogyan futnak egymás mellett a szálak, a szálakat egy ImageList-ben tárolt képsorozat elemeivel szimbolizálja. A programban egy időben több szál is fut, de a processzor egy időben csak eggyel foglalkozik, viszont cserélgeti a futó szálakat.

A Piros ikonok az aktív szakaszt mutatják, a sárgák az aktív szakasz utáni alvó periódust, a kék ikonok pedig a még feldolgozásra váró, és a már nem futó szálakat szimbolizálják. A programban szerepel egy célfüggvény, mely a szálakhoz rendelt eseményt hajtja végre. Az egyszerűség kedvéért a program célfüggvénye csak a szál ikonját és feliratát cserélgeti, ezzel jelezve, hogy egy valós, párhuzamos program ezen részében adatfeldolgozás, vagy egyéb fontos esemény történik.

Az egyszerre futó szálak számát nem a programozó határozza meg, hanem a .NET keretrendszer az erőforrások függvényében.

Induláskor közöljük a programmal a futtatni kívánt szálak számát, majd átadjuk a célfüggvényt a System.Threading.ThreadPool.QueueUserWorkItem() metódusnak, mely feldolgozza ezeket.

A célfüggvény mellett adhatunk a metódusnak egy tetszőleges objektumot, melyben paramétereket közölünk vele, ami átadja ezeket a célfüggvénynek.

A példában az egy mezőt tartalmazó Parameterek osztályt adunk át a paraméter listában, melyben az adott elem sorszámát közöljük a célfüggvénnyel.

class Parameterek

{

public int i = 0;

public String s = ”Szál”;

}

A program indulása után a Form- ra helyezett nyomógomb indítja el a szálkezelést.

A nyomógomb eseménykezelőjében, a FOR ciklusban példányosítjuk a Parameterek osztályt (minden szálhoz egyet):

Parameterek P = new Parameterek();

Hozzáadjuk a soron következő elemet a listView komponenshez, beállítjuk az elem ikonját és feliratát:

listView1.Items.Add(Convert.ToString(i)+"Szál",2);

Értékül adjuk a ciklus változóját az osztály i változójának, ezzel átadva az adott szál sorszámát a szálkezelőnek, s közvetett úton a célfüggvénynek:

P.i=i;

Végül átadjuk a példányt a célfüggvénnyel együtt a szálkezelőnek, mely gondoskodik a szál sorsáról. Ütemezi, futtatja, majd leállítja azt.

System.Threading.WaitCallback CF = new System.Threading.WaitCallback(CelF);

System.Threading.ThreadPool.QueueUserWorkItem(CF ,P);

A célfüggvény a következő dolgokat végzi el, szimulálva egy valós program-szál működését:

  1. Beállítja a szál ikonját a piros, „futó” ikonra, (Az ikonokat egy imageList- ből veszi), azután átírja az ikon feliratát:

listView1.Items[atadot.i].ImageIndex=0;

listView1.Items[atadot.i].Text="Futó szál";

  1. A System.Thread.Threading.Sleep(1000) metódussal a szálkezelő várakoztatja a szálat, majd átállítja a szálhoz tartozó ikont a sárga, „alvó” ikonra, a feliratát pedig „Alvó szál” - ra:

listView1.Items[atadot.i].ImageIndex=1;

listView1.Items[atadot.i].Text="Alvó szál";

System.Threading.Thread.Sleep(1000);

  1. A szál ismét várakozik, majd az ikonja az eredetire vált:

listView1.Items[atadot.i].ImageIndex=2;

listView1.Items[atadot.i].Text="Vége”);

System.Threading.Thread.Sleep(1000);

Mivel a szálak létrehozását ciklusba szerveztük, a program annyi szálat hoz létre, mint a ciklus lépésszáma, viszont azt, hogy egyszerre hány szál fut, a szálkezelő dönti el.

A listView ablakában látszik, hogy egyszerre akár három, vagy négy szál is futhat, és mellettük néhány szál éppen alszik, de lassabb gépeken ezek a számok növekedhetnek.

Sajnos a többszálú programozás közel sem ilyen egyszerű. Bonyolultabb alkalmazások esetén egy probléma mindenképpen felvetődik. A futó szálak nem használják egy időben ugyanazt az erőforrást, vagyis biztonságosan kell futniuk egymás mellett. A jól megírt többszálú programok optimálisan használják fel az osztott erőforrásokat, de csak akkor használjuk fel a lehetőségeiket, ha tisztában vagyunk a használatukban rejlő előnyökkel, és a lehetséges hibákkal is. A rosszul megírt párhuzamos működésű programokkal éppen az ellenkezőjét érjük el annak, amit szeretnénk. Növeljük a lépésszámot, a memória foglaltságát és a programok hatékonyságát.