ThreadStart avec paramètres


261

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


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

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) {
  ...
}

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.


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


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

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..
}



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


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

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.


3

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

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);


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`
    }
}

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

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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.