Szoftverfejlesztés .NET platformon - Jegyzet 7. fejezet
Ez az oldal a korábbi SCH wikiről lett áthozva.
Ha úgy érzed, hogy bármilyen formázási vagy tartalmi probléma van vele, akkor, kérlek, javíts rajta egy rövid szerkesztéssel!
Ha nem tudod, hogyan indulj el, olvasd el a migrálási útmutatót.
70-536 .NET framework 2.0 Application Development Foundation
%TOC{depth="3"}%
Szálak
=System.Threading= névtér
Előny: felhasználói élmény növelése, nagyobb processzor kihasználtság.
A szálak memóriaterülete közös, a processzeké különböző.
Thread osztály
- =IsAlive=: éppen fut-e
- =IsBackground=: háttér szál-e. A háttér szálak a programból való kilépéskor automatikusan lelövődnek.
- =IsThreadpoolThread=: thread pool-ból lett-e lekérve
- =Name=: név lekérdezése és megváltoztatása
- =Priority=: prioritás lekérdezése és megváltoztatása.
Lehetséges értékei: =Highest=, =AboveNormal=, =Normal=, =BelowNormal=, =Lowest=
- =ThreadContext CurrentContext=
- =CurrentPrincipal=: a szálat futtató felhasználó
- =CurrentThread= (statikus)
- =Start()=: szál indításának ütemezése
- =Join()=: szál befejeződésének megvárása
- =Sleep()=: aktuális szál várakoztatása (statikus)
ThreadState
- =Suspended= (deprecated)
- =Aborted=
- =AbortRequested=
- =Background=: az alkalmazás végén automatikusan lelövi
- =Running=
- =Stopped=
- ...
Szálak indítása és leállítása
- =ThreadStart= objektum létrehozása (prioritás, stb. megadása)
(szálkezelő függvény: =void Foo()=) vagy
=ParameterizedThreadStart= létrehozása
(szálkezelő függvény:
void Foo(object parameter)
)
- =Thread= létrehozása
- Szál elindítása
Szál indítása paraméter nélkül
static void SimpleWork() { Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId); } Thread thread = new Thread(new ThreadStart(SimpleWork)); thread.Start();
Szál indítása paraméterrel
static void WorkWithParameter(object o) { Console.WriteLine("{0}: {1}", o, Thread.CurrentThread.ManagedThreadId); } ParameterizedThreadStart operation = new ParameterizedThreadStart(WorkWithParameter); Thread thread1 = new Thread(operation); thread1.Start("Hello"); Thread thread2 = new Thread(operation); thread2.Start("Goodbye");
Szál bevárása
A =thread.Join()= hívás blokkolja az aktuális szálat, amíg a =thread= szál futása be nem fejeződik.
Szál megszakítása
A =thread.Abort()= hívás megszakítja a szál futását. A futás aktuális pozícióján dob egy
ThreadAbortException
-t, amit a szálkezelő függvény elkaphat és lekezelhet. A szál megszakítása inkonzisztens állapothoz vezethet, ezért a szálkezelő rendszerrel tudatni kell, hogy hol szakítható meg a szál futása. A =Thread.BeginCriticalRegion()= és a =Thread.EndCriticalRegion()= közötti kód nem szakítható meg
Abort
-tal.
Execution Context
Tartalmazza
- a futtató usert (=IPrincipal=),
- a lokalizációs beállításokat és
- a tranzakciós beállításokat.
Metódusai
- =ExecutionContext.SuppressFlow()=: az automatikus context átadás kikapcsolása (gyorsítja a szál váltást)
- =ExecutionContext.RestoreFlow()=: visszakapcsolás
- =ExecutionContext.Capture()=: aktuális context lekérdezése
- =ExecutionContext.Run(context, ContextCallback)=: metódus futtatása adott contexttel
Szinkronizáció
Ha a szálak közös memóriaterületet használnak, szinkronizálni kell a hozzáférést.
Könnyűsúlyú objektumok
=Interlocked= osztály: 5 műveletet tud atomi módon elvégezni
- =Add()=: két szám összeadása
- =Decrement()=: szám csökkentése
- =Exchange()=: két szám megcserélése
- =Increment()=: számot növel. Pl. =Interlocked.Increment(ref counter);=
- =Read()=: 64 bites számot atomi műveletként olvas be
Monitor
- =TryEnter()=: próbál lockolni, timeout megadható (pl.
Timeout.Infinite
) - =Enter(object)=: lockol, csak referencia típusú paramétert fogad el
- =Exit(object)=: elengedi a zárat
- =Wait()=: elengedi a zárat és vár, amíg nem kaphatja meg újra
=lock=:
Monitor
-ra fordul.
lock(obj) { op; }
jelentése
Monitor.Enter(obj); try { op; } finally { Monitor.Exit(obj); }
=ReaderWriterLock=: olvasási és írási lock külön kérhető
- =IsReaderLockHeld=, =IsWriterLockHeld=
- ={Acquire|Release}{ReaderWriter}Lock=. A zár kérésénél megadható timeout, ha lejár,
ApplicationException
-t dob. - ={UpgradeTo|DowngradeFrom}WriterLock=: olvasási ↔ írási lock átalakítás
Kernel objektumok
- Közös ősosztály: =WaitHandle=
- =WaitOne()=: elkérés
- =Close()=: felszabadítás
- =Mutex=:
AppDomain
-ek és processzek között is működik,
33x lassabb a
Monitor
-nál
- =new Mutex(false, "CommonMutex")=: processzek közötti mutex létrehozása
- =Mutex.OpenExisting("name")=: létező mutexre referencia kérése
- =Semaphore=
- =new Semaphore(currentSlots, maximumSlots)=: névtelen szemafor létrehozása
- =new Semaphore(currentSlots, maximumSlots, name)=: névvel ellátott szemafor létrehozása
- =Semaphore.OpenExisting("name")=: létező szemaforra referencia kérése
(ha nem létezik,
WaitHandleCannotBeOpenedException
-t dob)
- =Event=: két állapota van: jelzett és jelzetlen. Várakozni lehet a jelzett állapotára.
- Metódusai: =Set()=, =Reset()=
- =AutoResetEvent=: azonos a működése a
Mutex
-szel? - =ManualResetEvent=: ha jelzettre vált, a
Mutex
-szel ellentétben az összes rá váró
szál továbbfut; csak =Reset()= hívásra vált vissza jelzetlenre.
Aszinkron programozás
=BeginXXX= és =EndXXX= metódusok.
Aszinkron hívási modellek
- Wait-Until-Done: =EndXXX= meghívásakor megvárja a metódus befejeződését
- Polling: A =BeginXXX=
IAsyncResult
-tal tér vissza, amit lehet kérdezgetni, hogy készen van-e (IsCompleted
property) - Callback: befejeződéskor delegate viszahívása. A =BeginXXX= hívásakor át kell adni plusz paraméterként a callback függvényt.
- Ha
BeginRead
-del olvasunk egy streamet, a callback függvénynek nem csak a puffert kell átadni, hanem a streamet is, hogy le tudja zárni.
- Ha
Példa aszinkron olvasásra callback függvénnyel
static byte[] buffer = new byte[100]; static void AsyncRead() { string filename = Environment.SystemDirectory + "\\mfc71.pdb"; FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous); IAsyncResult result = strm.BeginRead( buffer, 0, buffer.Length, new AsyncCallback(CompleteRead), fs); } static void CompleteRead(IAsyncResult result) { Console.WriteLine("Read Completed"); FileStream fs = (FileStream) result.AsyncState; // az EndRead() nem fog blokkolódni int numBytes = fs.EndRead(result); fs.Close(); Console.WriteLine("Read {0} Bytes", numBytes); Console.WriteLine(BitConverter.ToString(buffer)); }
Hibakezelés
Csak az =EndXXX= dobhat exceptiont, mivel a =BeginXXX= által dobott kivételeket a hívó nem tudja lekezelni.
Az aszinkron hívás során keletkező kivételek nem csak az =EndXXX= híváskor, hanem azonnal is lekezelhetők, ha feliratkozunk az =Application.ThreadException= eseményre.
Thread pool
Túl sok szál alkalmazása "vergődéshez" vezethet, azaz az operációs rendszer több időt tölt context switchinggel, mint a valódi végrehajtással. A =ThreadPool= használata javít a helyzeten
=ThreadPool=: háttér szálakat tárol.
- =ThreadPool.QueueUserWorkItem(threadMethod, parameter)=: meghív egy metódust új szálon
- =ThreadPool.UnsafeQueueUserWorkItem()=: -"-, de a context információt nem adja át
- =ThreadPool.RegisterWaitForSingleObject()=:
WaitHandle
-höz lehet callback függvényt
regisztrálni
- =ThreadPool.[Get|Set][MinMax]Threads()=
static void WorkWithParameter(object state) { // ... } WaitCallback workItem = new WaitCallback(WorkWithParameter); ThreadPool.QueueUserWorkItem(workItem, "ThreadPooled");
SynchronizationContext
Üzenetkezelésre használják
- =SynchronizationContext.Current.Send()=: szinkron módon küld üzenetet
- =SynchronizationContext.Current.Post()=: aszinkron módon küld üzenetet
(a Windows Forms szálkezelési modell ezt nem támogatja, ott a =Post()= is szinkron módon működik)
System.Threading.Timer
Ez az kernel szintű timer, a =System.Timers.Timer= és a =Windows.Forms.Timer= csak burkoló osztály. Pontossága: 55 ms
Konstruktor paraméterei:
- =TimerCallback callback=
- callback függvény argumentuma
- =dueTime=: mennyi idő múlva hívja meg a callbacket először
- =interval=: mennyi időnként hívja meg a callbacket
- =Change(dueTime, interval)=: menet közben is megváltoztathatók az előbbi értékek. Leállítani úgy lehet, ha
dueTime
-nakTimeout.Infinite
-et adunk meg.
-- Peti - 2007.06.27.