Wie startet man einen Thread mit Parametern in C #?
Wie startet man einen Thread mit Parametern in C #?
Antworten:
Ja:
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }sollte Parametertyp habenobject
ParameterizedThreadStartund dies eindeutig aus dem Fragentext hervorgeht, ist dies wahrscheinlich nicht der Fall.
Bei einer der beiden Überladungen des Thread-Konstruktors wird ein ParameterizedThreadStart-Delegat verwendet, mit dem Sie einen einzelnen Parameter an die Startmethode übergeben können. Leider erlaubt es nur einen einzigen Parameter und dies auf unsichere Weise, da es als Objekt übergeben wird. Ich finde es viel einfacher, einen Lambda-Ausdruck zu verwenden, um die relevanten Parameter zu erfassen und sie stark typisiert zu übergeben.
Versuche Folgendes
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))
Sie können Lambda-Ausdrücke verwenden
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
Dies ist bisher die beste Antwort, die ich finden konnte. Sie ist schnell und einfach.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Der Parametertyp muss ein Objekt sein.
BEARBEITEN:
Obwohl diese Antwort nicht falsch ist, empfehle ich gegen diesen Ansatz. Die Verwendung eines Lambda-Ausdrucks ist viel einfacher zu lesen und erfordert keine Typumwandlung. Siehe hier: 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"
}
}
Einfache Möglichkeit mit Lambda wie so ..
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
ODER Sie könnten sogar delegatemit , ThreadStartwie so ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
ODER mit VS 2019 .NET 4.5+ noch sauberer wie so ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Verwenden Sie ParametrizedThreadStart.
Wie bereits in verschiedenen Antworten erwähnt, bietet die ThreadKlasse derzeit (4.7.2) mehrere Konstruktoren und eine StartMethode mit Überladungen.
Diese relevanten Konstruktoren für diese Frage sind:
public Thread(ThreadStart start);
und
public Thread(ParameterizedThreadStart start);
die entweder einen ThreadStartDelegierten oder einen ParameterizedThreadStartDelegierten nehmen.
Die entsprechenden Delegierten sehen folgendermaßen aus:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Wie zu sehen ist, scheint der richtige Konstruktor derjenige zu sein, der einen ParameterizedThreadStartDelegaten nimmt, so dass eine Methode, die der angegebenen Signatur des Delegaten entspricht, vom Thread gestartet werden kann.
Ein einfaches Beispiel für die Instanziierung der ThreadKlasse wäre
Thread thread = new Thread(new ParameterizedThreadStart(Work));
oder nur
Thread thread = new Thread(Work);
Die Signatur der entsprechenden Methode ( Workin diesem Beispiel aufgerufen ) sieht folgendermaßen aus:
private void Work(object data)
{
...
}
Was bleibt, ist den Thread zu starten. Dies erfolgt entweder mit
public void Start();
oder
public void Start(object parameter);
Während Start()der Thread gestartet und nullals Daten an die Methode übergeben würde, Start(...)kann verwendet werden, um alles an die WorkMethode des Threads zu übergeben.
Bei diesem Ansatz gibt es jedoch ein großes Problem: Alles, was an die WorkMethode übergeben wird, wird in ein Objekt umgewandelt. Das heißt, innerhalb der WorkMethode muss es wieder wie im folgenden Beispiel in den ursprünglichen Typ umgewandelt werden:
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}");
}
Casting ist etwas, was Sie normalerweise nicht wollen.
Was ist, wenn jemand etwas anderes übergibt, das keine Zeichenfolge ist? Da dies zunächst nicht möglich zu sein scheint (weil es meine Methode ist, ich weiß, was ich tue oder die Methode privat ist, wie sollte jemand jemals etwas an sie weitergeben können? ), Können Sie möglicherweise aus verschiedenen Gründen genau diesen Fall haben . Da einige Fälle möglicherweise kein Problem darstellen, sind es andere. In solchen Fällen werden Sie wahrscheinlich eine haben, InvalidCastExceptiondie Sie wahrscheinlich nicht bemerken werden, weil sie den Thread einfach beendet.
Als Lösung würden erwarten , dass Sie ein generisch erhalten ParameterizedThreadStartDelegierten wie , ParameterizedThreadStart<T>wo Tdie Daten der Typ , der Sie in denen geben wollen wäre WorkMethode. Leider gibt es so etwas (noch?) Nicht.
Es gibt jedoch eine vorgeschlagene Lösung für dieses Problem. Dabei wird eine Klasse erstellt, die sowohl die an den Thread zu übergebenden Daten als auch die Methode enthält, die die Arbeitsmethode wie folgt darstellt:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Mit diesem Ansatz würden Sie den Thread folgendermaßen starten:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Auf diese Weise vermeiden Sie einfach das Herumwirbeln und haben eine typsichere Möglichkeit, Daten für einen Thread bereitzustellen ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Lengthist nicht möglich und so weiter)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }. Anstatt Ihre Threading-Methode zu verwenden Tasks<T>, fand ich die Verwendung etwas komfortabler , wie zum Beispiel tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))meine Antwort unten ( stackoverflow.com/a/59777250/7586301 )
Ich hatte ein Problem mit dem übergebenen Parameter. Ich habe eine Ganzzahl von einer for-Schleife an die Funktion übergeben und angezeigt, aber es wurden immer unterschiedliche Ergebnisse ausgegeben. wie (1,2,2,3) (1,2,3,3) (1,1,2,3) usw. mit ParametrizedThreadStart- Delegat.
Dieser einfache Code wirkte wie ein Zauber
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Das ParameterizedThreadStartnimmt einen Parameter. Sie können damit einen Parameter oder eine benutzerdefinierte Klasse mit mehreren Eigenschaften senden.
Eine andere Methode besteht darin, die Methode, die Sie als Instanzmitglied starten möchten, zusammen mit Eigenschaften für die Parameter, die Sie festlegen möchten, in eine Klasse einzufügen. Erstellen Sie eine Instanz der Klasse, legen Sie die Eigenschaften fest und starten Sie den Thread, der die Instanz und die Methode angibt. Die Methode kann dann auf die Eigenschaften zugreifen.
Sie können einen ParametrizedThreadStart- Delegaten verwenden:
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Sie können die BackgroundWorker RunWorkerAsync- Methode verwenden und Ihren Wert übergeben.
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`
}
}
Ich schlage vor, Task<T>anstelle von zu verwenden Thread; Es erlaubt mehrere Parameter und wird sehr gut ausgeführt.
Hier ist ein Arbeitsbeispiel:
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() + " ");
}
}
}
}