Multi-threading in C # met taken

De computer programmeren term "thread" is een afkorting van thread of execution, waarbij een processor een gespecificeerd pad door uw code volgt. Het concept van het volgen van meer dan één thread tegelijk introduceert het onderwerp multitasking en multithreading.

Een applicatie bevat een of meer processen. Beschouw een proces als een programma dat op uw computer draait. Elk proces heeft nu een of meer threads. Een gametoepassing heeft mogelijk een thread om bronnen van schijf te laden, een andere om AI te doen en een andere om de game als server uit te voeren.

In .NET / Windows wijst het besturingssysteem processortijd toe aan een thread. Elke thread houdt uitzonderingshandlers bij en de prioriteit waarop deze wordt uitgevoerd, en het heeft een plek om de threadcontext op te slaan totdat deze wordt uitgevoerd. Threadcontext is de informatie die de thread moet hervatten.

Multitasking met threads

Threads nemen een beetje geheugen in beslag en het maken ervan kost wat tijd, dus meestal wil je er niet veel gebruiken. Vergeet niet dat ze strijden om processortijd. Als uw computer meerdere CPU's heeft, kan Windows of .NET elke thread op een andere CPU uitvoeren, maar als meerdere threads draaien op dezelfde CPU, dan kan er maar één tegelijk actief zijn en het wisselen van threads duurt tijd.

instagram viewer

De CPU voert een thread uit voor een paar miljoen instructies en schakelt vervolgens over naar een andere thread. Alle CPU-registers, het huidige programma-uitvoeringspunt en de stapel moeten ergens worden opgeslagen voor de eerste thread en vervolgens worden hersteld van ergens anders voor de volgende thread.

Een thread maken

In het naamruimtesysteem. Threading, vindt u het draadtype. De constructor-thread (ThreadStart) maakt een exemplaar van een thread. Maar de laatste tijd C # code, is het waarschijnlijker dat het een lambda-expressie doorgeeft die de methode met alle parameters aanroept.

Als je het niet zeker weet lambda-uitdrukkingen, is het misschien de moeite waard om LINQ te bekijken.

Hier is een voorbeeld van een thread die is gemaakt en gestart:

systeem gebruiken;
systeem gebruiken. Draadsnijden;
naamruimte ex1
{
klasse programma
{
openbare statische leegte Write1 ()
{
Troosten. Schrijf ('1');
Draad. Slaap (500);
}
statische leegte Main (string [] args)
{
var task = new Thread (Write1);
taak. Start ();
voor (var i = 0; ik <10; ik ++)
{
Troosten. Schrijf ('0');
Troosten. Schrijf (taak. Is levend? 'ADVERTENTIE') ;
Draad. Slaap (150);
}
Troosten. ReadKey ();
}
}
}

Het enige dat dit voorbeeld doet, is "1" naar de console schrijven. De hoofdthread schrijft 10 keer een "0" naar de console, telkens gevolgd door een "A" of "D", afhankelijk van of de andere thread nog steeds Levend of Dood is.

De andere thread wordt maar één keer uitgevoerd en schrijft een '1'. Na de vertraging van een halve seconde in de thread Write1 () is de thread klaar en de taak. IsAlive in de hoofdlus retourneert nu "D."

Thread Pool en Task Parallel Library

In plaats van je eigen thread te maken, gebruik je een Thread Pool, tenzij je het echt nodig hebt. Vanaf .NET 4.0 hebben we toegang tot de Task Parallel Library (TPL). Net als in het vorige voorbeeld hebben we opnieuw een beetje LINQ nodig, en ja, het zijn allemaal lambda-expressies.

Tasks gebruikt de Thread Pool achter de schermen, maar maak beter gebruik van de threads, afhankelijk van het aantal dat wordt gebruikt.

Het belangrijkste object in de TPL is een taak. Dit is een klasse die een asynchrone bewerking vertegenwoordigt. De meest gebruikelijke manier om dingen te laten lopen, is met de taak. Fabriek. StartNieuw zoals in:

Taak. Fabriek. StartNew (() => DoSomething ());

Waar DoSomething () de methode is die wordt uitgevoerd. Het is mogelijk om een ​​taak te maken en deze niet onmiddellijk te laten uitvoeren. Gebruik in dat geval Taak als volgt:

var t = nieuwe taak (() => console. WriteLine ("Hallo"));
...
t. Begin();

Dat start de thread pas als de .Start () wordt aangeroepen. In het onderstaande voorbeeld staan ​​vijf taken.

systeem gebruiken;
systeem gebruiken. Draadsnijden;
systeem gebruiken. Threading. Taken;
naamruimte ex1
{
klasse programma
{
openbare statische leegte Write1 (int i)
{
Troosten. Schrijf (i);
Draad. Slaap (50);
}
statische leegte Main (string [] args)
{
voor (var i = 0; ik <5; ik ++)
{
var waarde = i;
var runningTask = Taak. Fabriek. StartNew (() => Write1 (waarde));
}
Troosten. ReadKey ();
}
}
}

Voer dat uit en je krijgt de cijfers 0 tot en met 4 output in een willekeurige volgorde zoals 03214. Dat komt omdat de volgorde van taakuitvoering wordt bepaald door .NET.

U vraagt ​​zich misschien af ​​waarom de var-waarde = i nodig is. Probeer het te verwijderen en schrijf Write (i) en je ziet iets onverwachts zoals 55555. Waarom is dit? Dit komt omdat de taak de waarde van i weergeeft op het moment dat de taak wordt uitgevoerd, niet wanneer de taak is gemaakt. Door een nieuwe te creëren variabel elke keer in de lus wordt elk van de vijf waarden correct opgeslagen en opgepakt.

instagram story viewer