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}");
}
}