ThreadStart mit Parametern

261

Wie startet man einen Thread mit Parametern in C #?

J L.
quelle
Die Antwort auf diese Frage ist in den verschiedenen Versionen der Laufzeit sehr unterschiedlich. Ist eine 3,5-Antwort in Ordnung?
Federbrecher
4
Beeindruckend. Ich habe einige Ihrer alten Fragen bearbeitet, aber es könnte ein Vollzeitjob sein. Ich hatte vergessen, wie sehr Sie sich im Laufe der Jahre verbessert haben. :-)
John Saunders
Wenn ich eine so kurze Frage stellen würde, würde ich 5 negative Punkte oder noch mehr bekommen! Obwohl mir die Frage und Antwort geholfen hat.
Mohammad Musavi

Antworten:

174

Ja:

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
Erick
quelle
14
Ist dies dasselbe: ThreadStart processTaskThread = delegate {ProcessTasks (databaseox.DataboxID); }; neuer Thread (processTaskThread) .Start ();
JL.
43
Was ist myParamObject und myUrl?
Dialex
3
In diesem Fall void MyParamObject(object myUrl){ //do stuff }sollte Parametertyp habenobject
Elshan
15
-1 Da die Antwort davon ausgeht, dass das OP weiß, wie es zu verwenden ist, ParameterizedThreadStartund dies eindeutig aus dem Fragentext hervorgeht, ist dies wahrscheinlich nicht der Fall.
JYelton
2
Ich habe diesen Fehler Fehler CS0123 Keine Überladung für 'UpdateDB' entspricht dem Delegaten 'ParameterizedThreadStart'
Omid Farvid
482

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) {
  ...
}
JaredPar
quelle
41
+1: Obwohl die aktuell ausgewählte Antwort absolut korrekt ist, ist diese von JaredPar die bessere. Es ist einfach die beste Lösung für die meisten praktischen Fälle.
Galaktor
2
Diese Lösung ist viel besser als die StandardparameterThreadStart
Piotr Owsiak
5
Schön so einfach. Schließen Sie einfach jeden Anruf in "new Thread (() => FooBar ()) .Start ();
Thomas Jespersen
12
Genial, das ist für VB.NET-LeuteDim thr As New Thread(Sub() DoStuff(settings))
Dr. böse
3
@bavaza Ich bezog mich nur auf die statische Typprüfung
JaredPar
141

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.

Georgi-it
quelle
6
Beste Lösung für einfache Fälle IMO
Dunc
1
was ist das =>? und wo finde ich weitere Informationen zur Syntax?
Nick
2
Dies ist ein Lambda-Ausdruck. Einige Informationen finden Sie unter folgenden Adressen: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it
1
Das hat bei mir funktioniert. Ich habe den ParameterizedThreadStart und Variationen davon ausprobiert, hatte aber keine Freude. Ich habe .NET Framework 4 in einer vermeintlich einfachen Konsolenanwendung verwendet.
Daniel Hollinrake
Dies funktioniert am besten für Leute, die an diese Art von Delegierten gewöhnt sind. Könnte für Anfänger schwierig zu verstehen sein. Dies ist jedoch für C # -Standards sauber. Die akzeptierte Antwort funktioniert bei mir nicht und ich habe keine Zeit herauszufinden, warum.
Bitterblue
37
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

Spencer Ruport
quelle
Warum helfen Sie mit einem Code, der nicht kompiliert wird;) Parameter?
Sebastian Xawery Wiśniowiecki
32
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"
    }
}
huseyint
quelle
3
Dies gibt mir "Keine Überlastung für 'DoWork' entspricht Delegat 'System.Threading.ParameterizedThreadStart'
anon58192932
1
Was wäre der Unterschied, wenn Sie gerade ThreadMethod in der Thread t-Initialisierung übergeben hätten?
Joe
Denken Sie daran, dass der Parametertyp vom Typ 'Objekt' sein muss
Kunal Uppal
28

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..
}
Meister Mick
quelle
8

Verwenden Sie ParameterizedThreadStart .

Justin Niessner
quelle
13
Das ist beängstigend :)
Thomas
6

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

Markus Safar
quelle
Wow, eine Ablehnung ohne Kommentar ... Entweder ist meine Antwort so schlecht wie die Besetzung oder der Leser hat nicht verstanden, worauf ich hier hinweisen wollte ;-)
Markus Safar
1
Ich fand Ihre Lösung sehr aufschlussreich, herzlichen Glückwunsch. Ich wollte nur hinzufügen, dass ich bereits in Net.Core Folgendes getestet und ohne explizite Besetzung gearbeitet habe! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford
@ PaulEfford Danke ;-) Deine Lösung scheint ziemlich nett zu sein. Sie erhalten jedoch keinen Zugriff auf typspezifische Informationen, da diese weiterhin in einem Objekt gespeichert werden, oder? (zB message.Lengthist nicht möglich und so weiter)
Markus Safar
1
richtig ... Sie könnten message.GetType () und cast, wenn Sie eine bestimmte Eigenschaft wie benötigen 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 )
Paul Efford
5

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; 
}
user3805007
quelle
4

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.

Guffa
quelle
3

Sie können einen ParametrizedThreadStart- Delegaten verwenden:

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
CMS
quelle
1
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`
    }
}
Mohammed Hassen Ismaile
quelle
0

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;
        }
    }
Paul Efford
quelle
-2
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() + " ");
            }
        }
    }
}
Mohammed Hassen Ismaile
quelle
Mit Multithreading mit C # -Threads können Sie effizientere Anwendungen entwickeln, die über den gemeinsam genutzten Speicher synchronisiert werden.
Mohammed Hassen Ismaile