ThreadStart avec paramètres

261

Comment démarrer un thread avec des paramètres en C #?

JL.
la source
La réponse à cette question varie considérablement selon les versions du runtime - une réponse 3.5 est-elle correcte?
quillbreaker
4
Sensationnel. J'ai édité certaines de vos anciennes questions, mais cela pourrait être un travail à temps plein. J'avais oublié, euh, combien vous vous êtes amélioré au fil des ans. :-)
John Saunders
Si je posais une question aussi brève, j'obtiendrais 5 scores négatifs ou même plus! Bien que la question et la réponse m'ont aidé.
Mohammad Musavi

Réponses:

174

Ouais:

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
Erick
la source
14
est-ce la même: ThreadStart processTaskThread = delegate {ProcessTasks (databox.DataboxID); }; nouveau Thread (processTaskThread) .Start ();
JL.
43
Qu'est-ce que myParamObject et myUrl?
dialex
3
Dans ce cas, void MyParamObject(object myUrl){ //do stuff }devrait avoir le type de paramètreobject
Elshan
15
-1 car la réponse suppose que l'OP sait utiliser ParameterizedThreadStartet clairement à partir du texte de la question, ce n'est probablement pas le cas.
JYelton
2
J'ai cette erreur Erreur CS0123 Aucune surcharge pour «UpdateDB» ne correspond au délégué «ParameterizedThreadStart»
Omid Farvid
482

L'une des 2 surcharges du constructeur Thread utilise un délégué ParameterizedThreadStart qui vous permet de passer un seul paramètre à la méthode de démarrage. Malheureusement, il ne permet qu'un seul paramètre et il le fait de manière dangereuse car il le passe en tant qu'objet. Je trouve qu'il est beaucoup plus facile d'utiliser une expression lambda pour capturer les paramètres pertinents et les transmettre de manière fortement typée.

Essayez ce qui suit

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
la source
41
+1: Même si la réponse actuellement sélectionnée est absolument correcte, celle de JaredPar est la meilleure. C'est tout simplement la meilleure solution pour la plupart des cas pratiques.
galaktor
2
Cette solution est bien meilleure que la version standard ParameterizedThreadStart
Piotr Owsiak
5
Nice so simple. Enveloppez simplement n'importe quel appel dans "nouveau Thread (() => FooBar ()) .Start ();
Thomas Jespersen
12
Génial, c'est pour les gars VB.NETDim thr As New Thread(Sub() DoStuff(settings))
dr. evil
3
@bavaza Je faisais juste référence à la vérification de type statique
JaredPar
141

Vous pouvez utiliser des expressions lambda

private void MyMethod(string param1,int param2)
{
  //do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();

c'est jusqu'à présent la meilleure réponse que j'ai pu trouver, c'est rapide et facile.

Georgi-it
la source
6
Meilleure solution pour les cas simples IMO
Dunc
1
qu'est-ce que c'est =>? et où puis-je trouver plus d'informations sur la syntaxe?
Nick
2
Il s'agit d'une expression lambda, des informations peuvent être trouvées sur ces adresses: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it
1
Cela a fonctionné pour moi. J'ai essayé le ParameterizedThreadStart et ses variantes mais je n'ai pas eu de joie. J'utilisais .NET Framework 4 dans une application console soi-disant simple.
Daniel Hollinrake
Cela fonctionne mieux pour les personnes habituées à ce type de délégués. Cela pourrait être difficile pour les débutants de se tenir debout. C'est propre pour les normes C # cependant. La réponse acceptée ne fonctionne pas pour moi et je n'ai pas le temps de savoir pourquoi.
Bitterblue
37
Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param)
{
    string Parameter = (string)param;
}

Le type de paramètre doit être un objet.

ÉDITER:

Bien que cette réponse ne soit pas incorrecte, je déconseille cette approche. L'utilisation d'une expression lambda est beaucoup plus facile à lire et ne nécessite pas de transtypage de type. Voir ici: https://stackoverflow.com/a/1195915/52551

Spencer Ruport
la source
Pourquoi aidez-vous avec un code qui ne compile pas;) 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
la source
3
Cela me donne "aucune surcharge pour le délégué de matches 'DoWork' 'System.Threading.ParameterizedThreadStart'
anon58192932
1
Quelle serait la différence si vous veniez de passer ThreadMethod dans l'initialisation de Thread t?
Joe
N'oubliez pas que le type de paramètre doit être de type «objet»
Kunal Uppal
28

Un moyen simple d'utiliser lambda comme ça ..

Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();

OU vous pourriez même delegateutiliser ThreadStartcomme ça ...

ThreadStart ts = delegate
{
     bool moreWork = DoWork("param1", "param2", "param3");
     if (moreWork) 
     {
          DoMoreWork("param4", "param5");
     }
};
new Thread(ts).Start();

OU en utilisant VS 2019 .NET 4.5+ encore plus propre comme ça ..

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING..
    void ts()
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    }
    new Thread(ts).Start();
    //DO SOMETHING..
}
Maître Mick
la source
6

Comme cela a déjà été mentionné dans diverses réponses ici, la Threadclasse actuellement (4.7.2) fournit plusieurs constructeurs et une Startméthode avec des surcharges.

Ces constructeurs pertinents pour cette question sont:

public Thread(ThreadStart start);

et

public Thread(ParameterizedThreadStart start);

qui soit prendre un ThreadStartdélégué ou un ParameterizedThreadStartdélégué.

Les délégués correspondants ressemblent à ceci:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

Donc, comme on peut le voir, le constructeur correct à utiliser semble être celui qui prend un ParameterizedThreadStartdélégué afin qu'une certaine méthode conforme à la signature spécifiée du délégué puisse être démarrée par le thread.

Un exemple simple d'instanciation de la Threadclasse serait

Thread thread = new Thread(new ParameterizedThreadStart(Work));

ou juste

Thread thread = new Thread(Work);

La signature de la méthode correspondante (appelée Workdans cet exemple) ressemble à ceci:

private void Work(object data)
{
   ...
}

Ce qui reste est de démarrer le fil. Cela se fait en utilisant soit

public void Start();

ou

public void Start(object parameter);

Alors Start()que démarrerait le thread et passerait nullcomme données à la méthode, Start(...)peut être utilisé pour passer n'importe quoi dans la Workméthode du thread.

Il y a cependant un gros problème avec cette approche: tout ce qui est passé dans la Workméthode est converti en objet. Cela signifie que dans la Workméthode, il doit à nouveau être converti en type d'origine, comme dans l'exemple suivant:

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



Le casting est quelque chose que vous ne voulez généralement pas faire.

Et si quelqu'un passe quelque chose d'autre qui n'est pas une chaîne? Comme cela ne semble pas possible au début (car c'est ma méthode, je sais ce que je fais ou la méthode est privée, comment quelqu'un devrait-il pouvoir lui transmettre quoi que ce soit? ), Vous pouvez éventuellement vous retrouver exactement avec ce cas pour diverses raisons . Comme certains cas peuvent ne pas être un problème, d'autres le sont. Dans de tels cas, vous vous retrouverez probablement avec unInvalidCastException que vous ne remarquerez probablement pas car il termine simplement le thread.

Comme solution, vous vous attendez à obtenir un ParameterizedThreadStartdélégué générique comme ParameterizedThreadStart<T>Tserait le type de données que vous souhaitez transmettre à la Workméthode. Malheureusement, quelque chose comme ça n'existe pas (encore?).

Il existe cependant une solution suggérée à ce problème. Cela implique de créer une classe qui contient les deux, les données à transmettre au thread ainsi que la méthode qui représente la méthode de travail comme ceci:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

Avec cette approche, vous commenceriez le fil comme ceci:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

Donc, de cette façon, vous évitez simplement de lancer et d'avoir un moyen sûr de fournir des données à un thread ;-)

Markus Safar
la source
Wow, un downvote sans commentaire ... Soit ma réponse est aussi mauvaise que le casting soit le lecteur n'a pas compris ce que j'ai essayé de souligner ici ;-)
Markus Safar
1
J'ai trouvé votre solution très éclairée, félicitations. Je voulais juste ajouter que j'ai déjà testé dans Net.Core ce qui suit et travaillé sans avoir à lancer explicitement! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford
@PaulEfford Merci ;-) Votre solution semble plutôt sympa. Mais vous n'avez pas accès à des informations spécifiques au type car elles seront toujours encadrées par un objet, non? (par exemple message.Lengthn'est pas possible et ainsi de suite)
Markus Safar
1
à droite ... vous pouvez envoyer un message. GetType () et cast si requis une propriété spécifique comme if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }. Quoi qu'il en soit, au lieu d'utiliser votre méthode de filetage, j'ai trouvé un peu plus confortable à utiliser Tasks<T>, comme par exemple tasks.Add(Task.Run(() => Calculate(par1, par2, par3))), voir ma réponse ci-dessous ( stackoverflow.com/a/59777250/7586301 )
Paul Efford
5

J'avais un problème dans le paramètre passé. J'ai passé un entier d'une boucle for à la fonction et je l'ai affiché, mais cela donnait toujours des résultats différents. comme (1,2,2,3) (1,2,3,3) (1,1,2,3) etc. avec le délégué ParametrizedThreadStart .

ce code simple fonctionnait comme un charme

Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param) 
{
 string Parameter = (string)param; 
}
user3805007
la source
4

Le ParameterizedThreadStartprend un paramètre. Vous pouvez l'utiliser pour envoyer un paramètre ou une classe personnalisée contenant plusieurs propriétés.

Une autre méthode consiste à placer la méthode que vous souhaitez démarrer en tant que membre d'instance dans une classe avec les propriétés des paramètres que vous souhaitez définir. Créez une instance de la classe, définissez les propriétés et démarrez le thread en spécifiant l'instance et la méthode, et la méthode peut accéder aux propriétés.

Guffa
la source
3

Vous pouvez utiliser un délégué ParametrizedThreadStart :

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
CMS
la source
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
la source
0

Je propose d'utiliser Task<T>au lieu de Thread; il permet plusieurs paramètres et s'exécute très bien.

Voici un exemple de travail:

    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
la source
-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
la source
Le multi-threading avec C # Threads vous permet de développer des applications plus efficaces en synchronisant via la mémoire partagée.
Mohammed Hassen Ismaile