Hoofdstuk 7 - Les 2

ThreadPool.QueueUserItem is voldoende wanneer een thread wordt gestart en zolang laat lopen totdat de gespecificeerde methode klaar is met uitvoeren. Indien meer controle nodig is, zoals het stoppen van een thread, kan er een Thread object gemaakt worden om vervolgens de Start methode aan te roepen. De thread kan dan geannuleerd worden door de methode Abort aan te roepen.
static void Main(string args[])
{
// Maak een thread object en geef een DoWork methode mee gebruik makend van een ThreadStart delegate
Thread DoWorkThread = new Thread(new ThreadStart(DoWork));

// Start de thread
DoWorkThread.Start();

// Wacht een seconde
Thread.Sleep(1000);

// Annuleer de thread
DoWorkThread.Abort();

Console.WriteLine("Main applicatie wordt gesloten");
Thread.Sleep(6000);
}

public static void DoWork()
{
Console.WriteLine("DoWork wordt gestart");

try
{
Thread.Sleep(1000);
}
catch(ThreadAbortException ex)
{
Console.WriteLine("DoWork is geannuleerd");
}
finally
{
Console.WriteLine("Hier kunnen bijvoorbeeld resources worden opgeruimd");
}

Console.WriteLine("DoWork is klaar met uitvoeren");
}
De output ziet er als volgt uit:
DoWork wordt gestart
DoWork is geannuleerd
Hier kunnen bijvoorbeeld resources worden opgeruimd
Main applicatie wordt gesloten


Met de Thread.Priority property kan de prioriteit van een thread worden aangegeven. De thread met de hoogste prioriteit eindigt als eerste. Standaard worden threads uitgevoerd met prioriteit normaal (middelste).

De status van een thread kan worden opgevraagd met de Thread.ThreadState property (readonly!). Threads kunnen in meerdere statussen verkeren.

Net zoals het file system gebruik maakt van file locks (zodat niet meerdere applicaties hetzelfde bestand kunnen bewerken) kan in de code gebruik gemaakt worden van de Monitor class om objecten te locken zodat deze niet kunnen worden aangepast door bewerkingen vanuit een andere thread. De lock keyword is hetzelfde als het aanroepen van de methodes Monitor.Start en Monitor.End.
public class Math
{
public int value1;
public int value2;
private int result;

public Math(int value1, int value2)
{
this.value1 = value1;
this.value2 = value2;
}

public void Add()
{
lock(this)
{
result = value1 + value2;
Console.WriteLine("Optellen: " + result);
}
}
}
Monitor kan enkel reference types locken.

Het lock keyword maakt geen onderscheid in lezen of schrijven. Het locked beide.

Door gebruik te maken van de ReaderWriterLock class kunnen meerdere threads een waarde gelijktijdig lezen. De ene keer dat het niet kan is als een waarde wordt bewerkt.

Interlocked is een alternatief om een resource te locken. Deze class biedt basis operaties aan op een thread-veilige manier. Interlocked kan atomische staitische operaties uitvoeren d.m.v. uitvoeren van static methods. Een atomische operatie kan neit gestoord worden door een andere thread.

Door Thread.Join aan te roepen wordt er gewacht totdat die thread klaar is met uitvoeren voordat er verder wordt gegaan met het programma. Als er op meerdere threads gewacht moet worden kan er gebruik gemaakt worden van de WaitHandle.WaitAll static methode met een AutoResetEvent array.
//Definieer een array met drie AutoResetEvent Waithandle
static AutoResetEvent[] waitHandles = new AutoResetEvents[]
{
new AutoResetEvent(false);
new AutoResetEvent(false);
new AutoResetEvent(false);
};

static void Main(string args[])
{
// Zet meerdere taken in de wachtrij in meerdere threads en wacht totdat alle threads klaar zijn met uitvoeren
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), new ThreadInfo(3000, waitHandles[0]));
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), new ThreadInfo(2000, waitHandles[1]));
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), new ThreadInfo(1000, waitHandles[2]));

WaitHandle.WaitAll(waitHandle);

Console.WriteLine("Main thread is klaar");
Console.ReadKey();
}

static void DoTask(Object state)
{
ThreadInfo ti = (ThreadInfo)state;
Thread.Sleep(ti.ms);

Console.WriteLine("Gewacht: " + ti.ms.ToString() + " ms.");
ti.are.Set();
}

public class ThreadInfo
{
public AutoResetEvent are;
public int ms;

public ThreadInfo(int ms, AutoResetEvent are)
{
this.ms = ms;
this.are = are;
}
}
De uitvoer is als volgt:
Gewacht: 1000 ms
Gewacht: 2000 ms
Gewacht: 3000 ms
Main thread is klaar

Naast WaitHandle.WaitAll bestaat ook WaitHandle.WaitAny, welke wacht totdat er 1 thread klaar is.

Reacties

Populaire posts van deze blog

[SQL Server] varchar vs nvarchar

MS Sql 70-461: Chapter 5

[C#] Class serialiseren en deserialiseren