Jak rozpocząć wątek z parametrami w C #?
Jak rozpocząć wątek z parametrami w C #?
Odpowiedzi:
Tak :
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
powinien mieć typ parametruobject
ParameterizedThreadStart
i wyraźnie z tekstu pytania, prawdopodobnie tak nie jest.
Jedno z 2 przeciążeń konstruktora wątków pobiera delegata ParameterizedThreadStart, który pozwala przekazać pojedynczy parametr do metody startowej. Niestety dopuszcza tylko jeden parametr i robi to w niebezpieczny sposób, ponieważ przekazuje go jako obiekt. Uważam, że o wiele łatwiej jest użyć wyrażenia lambda, aby uchwycić odpowiednie parametry i przekazać je w mocno typowy sposób.
Spróbuj wykonać następujące czynności
public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
var t = new Thread(() => RealStart(param1, param2));
t.Start();
return t;
}
private static void RealStart(SomeType param1, SomeOtherType param2) {
...
}
Dim thr As New Thread(Sub() DoStuff(settings))
Możesz użyć wyrażeń lambda
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
to jak dotąd najlepsza odpowiedź, jaką mogłem znaleźć, jest szybki i łatwy.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Typ parametru musi być obiektem.
EDYTOWAĆ:
Chociaż ta odpowiedź nie jest niepoprawna, odradzam takie podejście. Korzystanie z wyrażenia lambda jest znacznie łatwiejsze do odczytania i nie wymaga rzutowania tekstu. Zobacz tutaj: https://stackoverflow.com/a/1195915/52551
Parameter
?
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod));
t.Start("My Parameter");
}
static void ThreadMethod(object parameter)
{
// parameter equals to "My Parameter"
}
}
Prosty sposób z wykorzystaniem lambda tak…
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
LUB możesz nawet delegate
użyć ThreadStart
tak ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
LUB przy użyciu VS 2019 .NET 4.5+ jeszcze czystszy tak ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Zastosowanie ParametrizedThreadStart
.
Jak już wspomniano w różnych odpowiedziach tutaj, Thread
klasa obecnie (4.7.2) zapewnia kilka konstruktorów i Start
metodę z przeciążeniami.
Tymi odpowiednimi konstruktorami tego pytania są:
public Thread(ThreadStart start);
i
public Thread(ParameterizedThreadStart start);
które biorą ThreadStart
delegata lub ParameterizedThreadStart
delegata.
Odpowiedni delegaci wyglądają tak:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Jak można zauważyć, poprawnym konstruktorem do użycia wydaje się być ten, który bierze ParameterizedThreadStart
delegata, aby pewna metoda zgodna z określoną sygnaturą delegata mogła zostać uruchomiona przez wątek.
Prostym przykładem Thread
byłoby zainicjowanie klasy
Thread thread = new Thread(new ParameterizedThreadStart(Work));
Lub tylko
Thread thread = new Thread(Work);
Podpis odpowiedniej metody (wywołanej Work
w tym przykładzie) wygląda następująco:
private void Work(object data)
{
...
}
Pozostało rozpocząć wątek. Odbywa się to za pomocą jednego z nich
public void Start();
lub
public void Start(object parameter);
Chociaż Start()
uruchamia wątek i przekazuje null
dane do metody, Start(...)
może służyć do przekazywania wszystkiego do Work
metody wątku.
Jest jednak jeden duży problem z tym podejściem: wszystko przekazane do Work
metody jest rzutowane na obiekt. Oznacza to, że w ramach Work
metody należy ponownie rzutować na oryginalny typ, jak w poniższym przykładzie:
public static void Main(string[] args)
{
Thread thread = new Thread(Work);
thread.Start("I've got some text");
Console.ReadLine();
}
private static void Work(object data)
{
string message = (string)data; // Wow, this is ugly
Console.WriteLine($"I, the thread write: {message}");
}
Przesyłanie jest czymś, czego zwykle nie chcesz robić.
Co się stanie, jeśli ktoś przekaże coś innego, co nie jest łańcuchem? Ponieważ na początku wydaje się to niemożliwe (ponieważ jest to moja metoda, wiem, co robię lub metoda ta jest prywatna, w jaki sposób ktoś powinien być w stanie przekazać coś do niej? ), Być może z tego powodu możesz skończyć dokładnie z tą sprawą . Ponieważ niektóre przypadki mogą nie stanowić problemu, inne tak. W takich przypadkach prawdopodobnie skończysz z InvalidCastException
czymś, czego prawdopodobnie nie zauważysz, ponieważ po prostu kończy wątek.
Jako rozwiązanie można oczekiwać ogólnego ParameterizedThreadStart
delegata, na przykład, ParameterizedThreadStart<T>
gdzie T
byłby typ danych, które chcesz przekazać do Work
metody. Niestety coś takiego jeszcze nie istnieje (jeszcze?).
Istnieje jednak sugerowane rozwiązanie tego problemu. Polega ona na utworzeniu klasy, która zawiera zarówno dane, które mają być przekazywane do wątku, jak i metodę reprezentującą metodę roboczą w następujący sposób:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Przy takim podejściu zaczynasz wątek w następujący sposób:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
W ten sposób po prostu unikniesz przerzucania się i masz bezpieczny sposób dostarczania danych do wątku ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
nie jest możliwe itd.)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }
. W każdym razie zamiast korzystania z metody wątkowania uznałem, że jest to bardziej wygodne w użyciu Tasks<T>
, na przykład tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
zobacz moją odpowiedź poniżej ( stackoverflow.com/a/59777250/7586301 )
Miałem problem z przekazanym parametrem. Przekazałem do funkcji liczbę całkowitą z pętli for i wyświetliłem ją, ale zawsze dawała inne wyniki. jak (1,2,2,3) (1,2,3,3) (1,1,2,3) itd. z delegatem ParametrizedThreadStart .
ten prosty kod działał jako urok
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
ParameterizedThreadStart
Pobiera jeden parametr. Możesz użyć tego do wysłania jednego parametru lub niestandardowej klasy zawierającej kilka właściwości.
Inną metodą jest umieszczenie metody, którą chcesz uruchomić jako element instancji w klasie, wraz z właściwościami parametrów, które chcesz ustawić. Utwórz instancję klasy, ustaw właściwości i uruchom wątek, określając instancję i metodę, a metoda może uzyskać dostęp do właściwości.
Możesz użyć delegata ParametrizedThreadStart :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Możesz użyć metody RunWorkerAsync BackgroundWorker i przekazać swoją wartość.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Thread t1 =new Thread(new ParameterizedThreadStart(order1));
t1.IsBackground = true;//i can stope
t1.Start(x);
Thread t2=new Thread(order2);
t2.Priority = ThreadPriority.Highest;
t2.Start();
Console.ReadKey();
}//Main
static void order1(object args)
{
int x = (int)args;
for (int i = 0; i < x; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}`enter code here`
}
}
Proponuję używać Task<T>
zamiast Thread
; pozwala na wiele parametrów i działa naprawdę dobrze.
Oto działający przykład:
public static void Main()
{
List<Task> tasks = new List<Task>();
Console.WriteLine("Awaiting threads to finished...");
string par1 = "foo";
string par2 = "boo";
int par3 = 3;
for (int i = 0; i < 1000; i++)
{
tasks.Add(Task.Run(() => Calculate(par1, par2, par3)));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("All threads finished!");
}
static bool Calculate1(string par1, string par2, int par3)
{
lock(_locker)
{
//...
return true;
}
}
// if need to lock, use this:
private static Object _locker = new Object();"
static bool Calculate2(string par1, string par2, int par3)
{
lock(_locker)
{
//...
return true;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Thread t1 =new Thread(new ParameterizedThreadStart(order1));
t1.Start(x);
Thread t2=new Thread(order2);
t2.Priority = ThreadPriority.Highest;
t2.Start();
Console.ReadKey();
}//Main
static void order1(object args)
{
int x = (int)args;
for (int i = 0; i < x; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}
}
}