MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Thread-uri cu parametri și ParameterizedThreadStart

În articolul precedent am discutat despre cum să rulăm metode fără parametri în thread-uri separate. Dar ce facem dacă trebuie să transmitem anumiți parametri în thread?

Pentru acest scop se utilizează delegatul ParameterizedThreadStart, care este transmis în constructorul clasei Thread:

public delegate void ParameterizedThreadStart(object? obj);

Utilizarea delegatului ParameterizedThreadStart este foarte similară cu lucrul cu ThreadStart. Să vedem un exemplu:

using System.Threading;

// creăm noi thread-uri
Thread myThread1 = new Thread(new ParameterizedThreadStart(Print));
Thread myThread2 = new Thread(Print);
Thread myThread3 = new Thread(message => Console.WriteLine(message));

// pornim thread-urile
myThread1.Start("Hello");
myThread2.Start("Aloha");
myThread3.Start("Salut");

void Print(object? message) => Console.WriteLine(message);

La crearea thread-ului, în constructorul clasei Thread este transmis un obiect delegat ParameterizedThreadStart new Thread(new ParameterizedThreadStart(Print)), sau direct metoda care corespunde acestui delegat (new Thread(Print)), inclusiv sub formă de expresie lambda (new Thread(message => Console.WriteLine(message))).

Apoi, la pornirea thread-ului, în metoda Start() se transmite valoarea care este transmisă ca parametru metodei Print. În acest caz, vom obține următorul output pe consolă:

Salut
Hello
Aloha

Utilizând ParameterizedThreadStart, ne confruntăm cu o limitare: putem rula în al doilea thread doar o metodă care primește ca unic parametru un obiect de tip object?. Prin urmare, dacă dorim să folosim date de alte tipuri, în metodă trebuie să realizăm conversia tipurilor. De exemplu:

using System.Threading;

int number = 4;
// creăm un nou thread
Thread myThread = new Thread(Print);
myThread.Start(number);    // n * n = 16

// acțiuni executate în al doilea thread
void Print(object? obj)
{
   // aici ne așteptăm să primim un număr
   if (obj is int n)
   {
       Console.WriteLine($"n * n = {n * n}");
   }
}

În acest caz, trebuie să convertim suplimentar valoarea transmisă la tipul int pentru a o folosi în calcule.

Dar ce facem dacă trebuie să transmitem mai mulți parametri de tipuri diferite? În acest caz, putem defini propriile noastre tipuri:

using System.Threading;

Person tom = new Person("Tom", 37);
// creăm un nou thread
Thread myThread = new Thread(Print);
myThread.Start(tom);

void Print(object? obj)
{
   // aici ne așteptăm să primim un obiect Person
   if (obj is Person person)
   {
       Console.WriteLine($"Name = {person.Name}");
       Console.WriteLine($"Age = {person.Age}");
   }
}

record class Person(string Name, int Age);

Mai întâi definim o clasă specială Person, al cărei obiect va fi transmis în al doilea thread, iar în metoda Main îl transmitem în al doilea thread.

Totuși, există o limitare: metoda Thread.Start nu este tip-sigură, adică putem transmite orice tip și va trebui să convertim obiectul transmis la tipul dorit. Pentru a rezolva această problemă, este recomandat să declarăm toate metodele și variabilele utilizate într-o clasă specială, iar în programul principal să rulăm thread-ul prin ThreadStart. De exemplu:

using System.Threading;

Person tom = new Person("Tom", 37);
// creăm un nou thread
Thread myThread = new Thread(tom.Print);
myThread.Start();

record class Person(string Name, int Age)
{
   public void Print()
   {
       Console.WriteLine($"Name = {Name}");
       Console.WriteLine($"Age = {Age}");
   }
}
← Lecția anterioară Lecția următoare →