Krizsán Zoltán
Ha az algoritmus sokáig dolgozik, de el akarjuk kerülni a „fagyást”. Kisebb a költsége, mint az új folyamatnak. Programozás szempontjából is könnyebb, mint az IPC (fájl, osztott memória, …)
Létrehoz, elindít szálat
IsAlive Gets a value indicating that the current thread is currently executing. IsBackground Gets or sets whether the thread runs as a background thread. IsThreadPoolThread Gets whether this thread is a thread in the thread pool. ManagedThreadId Gets a number to identify the current thread. Not the same as the operating system’s thread ID. Name Gets or sets a name associated with the thread. Priority Gets or sets the priority of the thread. ThreadState Gets the ThreadState value for the thread.
Abort Raises a ThreadAbortException on the thread to indicate that the thread should be aborted. Interrupt Raises a ThreadInterruptedException when a thread is in a blocked state (ThreadState.WaitSleepJoin). If the thread never blocks, the interruption never happens. Join Blocks the calling thread until the thread terminates. Resume Deprecated. Do not use. Start Sets a thread to be scheduled for execution. Suspend Deprecated. Do not use.
1. Definiáljunk egy metódust! (nincs vé, nincs paraméter) 2. Hozzunk létre egy ThreadStart delegátum példányt! 3. Hozzunk létre egy új Thread példányt megadva az előző delegátumot! 4. Hívjuk meg a start metódust! (A fonálba fut a 1. metódus, majd leáll.)
static void SimpleWork() { Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId); } ThreadStart operation = new ThreadStart(SimpleWork); Thread theThread = new Thread(operation); theThread.Start();
ThreadStart operation = new ThreadStart(SimpleWork); for (int x = 1; x <= 5; ++x) { Thread theThread = new Thread(operation); theThread.Start(); }
Fő fonál (main thread) létrehozza a munka fonalakat (working thread), nyilvántartja azokat, amelyek a kiegészítő munkákat végzik. Grafikát, vezérlőket csak a fő szálból lehet használni! Amikor a fő szálnak szüksége van az eredményekre Join minden munka szálra a főszálból!
Highest The highest priority AboveNormal Higher priority than Normal Normal The default priority BelowNormal Lower than Normal Lowest The lowest priority
ThreadStart helyett ParameterizedThreadStart delegátum használata. A paraméter Object típusú, cast-olni kell! (as, is operátor) A paraméter aktuális értékét a Start metódusnak kell adni! theThread.Start("Hello");
Hívjuk a Thread.Abort metódust! Ennek hatására a szálban a ThreadAbortException kivétel dobódik! Vagy elkapjuk, vagy nem, de a fonál leáll!
Az Abort metódus megszakítja a normál futást, ami következtében inkonzistens lehet az alkalmazásunk. Ezt elkerülendő használjuk a kritikus szakaszt. Ezt nem szakíthatja meg a rendszert. Thread.BeginCriticalRegion(); SomeClass.IsValid = true; SomeClass.IsComplete = true; Thread.EndCriticalRegion();
Minden szálhoz tartoznak adatok: biztonsági, kultúra, tranzakció Elérni a ExecutionContext statikus metódusaival lehet azokat. Egy rendszer szintű szál kezeli ezeket az információkat (teljesítmény szükséglet). Felfüggesztés : AsyncFlowControl flow = ExecutionContext.SuppressFlow() Visszaállítás: ExecutionContext.RestoreFlow();
Interlocked lock{} Mutex …
public class Counter{ public static int Count; static void UpdateCount() { for (int x = 1; x <= 10000; ++x) { Counter.Count = Counter.Count + 1; }
ThreadStart starter = new ThreadStart(UpdateCount); Thread[] threads = new Thread[10]; for (int x = 0; x < 10; ++x) { threads[x] = new Thread(starter); threads[x].Start(); } for (int x = 0; x < 10; ++x) { threads[x].Join(); }
Hyper-Threading processzoroknál az eredmény nem 100,000 Mert az írás, olvasás nem atomi! Counter.Count++ művelet: Betöltik a változó értékét egy regiszterbe. Növelik a regiszter értékét. Új érték vissza a változóba.
Interlocked osztály használata. static void UpdateCount() { for (int x = 1; x <= 10000; ++x) { Interlocked.Increment(ref Counter.Count); }
public void UpdateCount() { Interlocked.Increment(ref _count); if (Count % 2 == 0){ Interlocked.Increment(ref _evenCount); } Újabb probléma: a 2. számláló rossz lesz Hiszen ugyanazt a szálat beengedi. Nem az összetett művelet védett csak a 2 kölün-külön!
public void UpdateCount() { lock (this) { _count = _count + 1; if (Count % 2 == 0) // An even number { _evenCount = _evenCount + 1; }
public void UpdateCount(){ Monitor.Enter(this); try{ _count = _count + 1; if (Count % 2 == 0) // An even number { _evenCount = _evenCount + 1; } finally{ Monitor.Exit(this); }
Több lehetőség adódik a segítségével! Enter Creates an exclusive lock on a specified object Exit Releases an exclusive lock on a specified object TryEnter Attempts to create an exclusive lock on a specified object; optionally supports a timeout value on acquiring the lock Wait Releases an exclusive lock, and blocks the current thread until it can re-acquire the lock
Problémákat old meg, de újat vezet be: holtpont(deadlock) 2 erőforrás (1,2) 2 szál (A,B) A lokkolja 1-est és ugyanekkor B lokkolja 2- est majd ezután kellene A-nak a 2es és B-nek az 1es Mivel esek már lokkoltak mindkettő a másik által foglalt erőforrásra vár.
class Deadlocker{ object ResourceA = new Object(); object ResourceB = new Object(); } public void First(){ lock (ResourceA){ lock (ResourceB){ Console.WriteLine("First"); } public void First(){ lock (ResourceA){ lock (ResourceB){ Console.WriteLine("First"); } public void Second(){ lock (ResourceB){ lock (ResourceA){ Console.WriteLine("Second"); } public void Second(){ lock (ResourceB){ lock (ResourceA){ Console.WriteLine("Second"); }
Deadlocker deadlock = new Deadlocker(); ThreadStart firstStart = new ThreadStart(deadlock.First); ThreadStart secondStart = new ThreadStart(deadlock.Second); Thread first = new Thread(firstStart); Thread second = new Thread(secondStart); first.Start(); second.Start(); first.Join(); second.Join();
Monitor.TryEnter egy timeout érték múlva lemond a lokkolási kéréséről és kilép a saját lock-ból. Csökkentsük a legkisebbre a lokkolt kódot. Csökkent a lokkolási idő, így a holtpont kialakulásának esélye.
Különbséget teszt olvasási és írási lock között. Olvasási beenged többet is, de írásiba csak 1 et. Ha írják, nem lehet olvasni. UpgradeToWriterLock, DowngradeFromWriterLock
ReaderWriterLock rwLock = new ReaderWriterLock(); int counter = 0; try{ rwLock.AcquireReaderLock(100); rwLock.AcquireWriterLock(1000); try{ Console.WriteLine(counter); Interlocked.Increment(ref counter); } finally{ rwLock.ReleaseReaderLock();} } catch (ApplicationException){ Console.WriteLine("Failed to get a Lock"); }
Mutex theMutex = null; try // Try and open the Mutex{ theMutex = Mutex.OpenExisting("MYMUTEX"); } catch (WaitHandleCannotBeOpenedException){ // Cannot open the mutex because it doesn't exist } if (theMutex == null){ theMutex = new Mutex(false, "MYMUTEX"); } //használat if (theMutex.WaitOne(1000, false)) // wait 1 second for lock{ }
byte[] buffer = new byte[100]; string filename = string.Concat(Environment.SystemDirectory, "\\mfc71.pdb"); FileStream strm = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous); IAsyncResult result = strm.BeginRead(buffer, 0, buffer.Length, null, null); // Közben csinálhatunk bármit int numBytes = strm.EndRead(result); // amikor kell az eredmény strm.Close(); Console.WriteLine("Read {0} Bytes", numBytes); Console.WriteLine(BitConverter.ToString(buffer));