Aplikace může běžet v jednom nebo více vláknech (tocích), která se vykonávají "paralelně" v téže aplikaci.
![]() | |
using System;
using System.Threading;
class ThreadTest
{
static void Main(){
Thread t = new Thread(new ThreadStart(Run));
t.Start();
Run();
}
static void Run()
{
for(char c='a'; c<'z'; c++)
Console.Write(c);
}
} | |
V příkladu se zkonstruuje nový objekt vlákna předáním delegáta ThreadStart, který obaluje metodu, specifikující, kde má začít vykonávání daného vlákna. Pak se vlákno spustí a zavolá metodu Run(). Obě vlákna začnou vypisovat abecedu do konzole. Nevýhodou je, že sdílejí konzoli společně, takže se může (a pravděpodobně i stane), že budou obě abecedy zapletené do sebe.
Technika zajišťující koordinovaný přístup ke sdíleným prostředkům.
Příkaz lock zajišťuje, že k nějakému bloku kódu může přistoupit pouze jedno vlákno.
![]() | |
using System;
using System.Threading;
class LockTest
{
static void Main()
{
LockTest lt = new LockTest();
Thread t = new Thread(new ThreadStart(lt.Run));
t.Start();
lt.Run();
}
public void Run()
{
lock(this) {
for(char c='a'; c<'z'; c++)
Console.Write(c);
}
}
} | |
Výsledkem bude v konzoli dvakrát za sebou napsaná abeceda.
Operace umožňující vláknům navzájem komunikovat prostřednictvím monitoru, který udržuje seznam vláken čekajících na obdržení zámku nějakého objektu.
![]() | |
using System;
using System.Threading;
class MonitorTest
{
static void Main()
{
MonitorTest mt = new MonitorTest();
Thread t = new Thread(new ThreadStart(mt.Run));
t.Start();
mt.Run();
}
static void Run(){
for(char c='a'; c<'z'; c++)
lock(this)
{
Console.Write(c);
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
} | |
Metoda Pulse říká monitoru, aby vzbudil další vlákno, které čeká na zámek daného objektu. Volání metody Wait vlákno uspí. Výsledkem programu bude v konzoli napsaná zdvojená abeceda aabbccdd....
System.Threading.Monitor poskytuje implementaci Hoareho monitoru. Jde o nejzákladnější třídu vláken.
Získávají (resp. uvolňují) zámek nějakého objektu. Pokud nějaký objekt drží nějaké vlákno, pak metoda Enter() čeká, až bude zámek uvolněn nebo dokud není vlákno přerušeno výjimkou ThreadInterruptedException. Každému volání Enter() by mělo odpovídat volání Exit() pro tentýž objekt v tomtéž vlákně.
Je možné zavolat nějakou metodu asynchronně. Runtime nabízí standardní způsob asynchronního volání metod.
návratový-typ Invoke(seznam-parametrů);
Invoke() volá metodu asynchronně a volající musí čekat až delegát skončí vykonávání (standardní volání delegáta v C# volá Invoke())
IAsyncResult BeginInvoke(seznam-parametrů, IAsyncCallback ac, object stav);
návratový-typ EndInvoke(ref/out seznam-parametrů, IAsyncCallback ac);
BeginInvoke volá delegáta se zadaným seznamem parametrů a pak se okamžitě vrací. Toto volání se provede, je-li v ThreadPool k dispozici volné vlákno. EndInvoke přebírá návratovou hodnotu volané metody se všemi odkazovanými parametry a výstupními parametry. Mohlo totiž dojít k jejich změně.
![]() | |
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
delegate int Compute(string s);
class Class1
{
static int TimeConsumingFunction(string s)
{
return s.Length;
}
static void ViewResultFunction(IAsyncResult ar)
{
Compute c = (Compute)(((AsyncResult)ar).AsyncDelegate);
int result = c.EndInvoke(ar);
string s = (string)ar.AsyncState;
Console.WriteLine("{0} contains {1} chars", s, result);
}
static void Main()
{
Compute c = new Compute(TimeConsumingFunction);
AsyncCallback ac = new AsyncCallback(ViewResultFunction);
string s1 = "Christopher";
string s2 = "Nolan";
IAsyncResult ar1 = c.BeginInvoke(s1, ac, s1);
IAsyncResult ar2 = c.BeginInvoke(s2, ac, s2);
Console.WriteLine("Ready");
Console.Read();
}
} | |
Výstupem je:
![]() | |
Ready Christopher contains 11 chars Nolan contains 5 chars | |
![[ukázka kódu]](images/tip.png)