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 =newThread(newParameterizedThreadStart(myMethod));
t.Start(myParameterObject);
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
publicThreadStartTheThread(SomeType param1,SomeOtherType param2){var t =newThread(()=>RealStart(param1, param2));
t.Start();return t;}privatestaticvoidRealStart(SomeType param1,SomeOtherType param2){...}
+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
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.
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
classProgram{staticvoidMain(string[] args){Thread t =newThread(newParameterizedThreadStart(ThreadMethod));
t.Start("My Parameter");}staticvoidThreadMethod(object parameter){// parameter equals to "My Parameter"}}
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:
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
La signature de la méthode correspondante (appelée Workdans cet exemple) ressemble à ceci:
privatevoidWork(object data){...}
Ce qui reste est de démarrer le fil. Cela se fait en utilisant soit
publicvoidStart();
ou
publicvoidStart(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:
publicstaticvoidMain(string[] args){Thread thread =newThread(Work);
thread.Start("I've got some text");Console.ReadLine();}privatestaticvoidWork(object data){string message =(string)data;// Wow, this is uglyConsole.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>où 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:
publicclassThreadWithState{privatestring message;publicThreadWithState(string message){this.message = message;}publicvoidWork(){Console.WriteLine($"I, the thread write: {this.message}");}}
Avec cette approche, vous commenceriez le fil comme ceci:
ThreadWithState tws =newThreadWithState("I've got some text");Thread thread =newThread(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 .
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.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6{classProgram{staticvoidMain(string[] args){int x =10;Thread t1 =newThread(newParameterizedThreadStart(order1));
t1.IsBackground=true;//i can stope
t1.Start(x);Thread t2=newThread(order2);
t2.Priority=ThreadPriority.Highest;
t2.Start();Console.ReadKey();}//Mainstaticvoid order1(object args){int x =(int)args;for(int i =0; i < x; i++){Console.ForegroundColor=ConsoleColor.Green;Console.Write(i.ToString()+" ");}}staticvoid order2(){for(int i =100; i >0; i--){Console.ForegroundColor=ConsoleColor.Red;Console.Write(i.ToString()+" ");}}`enter code here`}}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6{classProgram{staticvoidMain(string[] args){int x =10;Thread t1 =newThread(newParameterizedThreadStart(order1));
t1.Start(x);Thread t2=newThread(order2);
t2.Priority=ThreadPriority.Highest;
t2.Start();Console.ReadKey();}//Mainstaticvoid order1(object args){int x =(int)args;for(int i =0; i < x; i++){Console.ForegroundColor=ConsoleColor.Green;Console.Write(i.ToString()+" ");}}staticvoid order2(){for(int i =100; i >0; i--){Console.ForegroundColor=ConsoleColor.Red;Console.Write(i.ToString()+" ");}}}}
Réponses:
Ouais:
la source
void MyParamObject(object myUrl){ //do stuff }
devrait avoir le type de paramètreobject
ParameterizedThreadStart
et clairement à partir du texte de la question, ce n'est probablement pas le cas.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
la source
Dim thr As New Thread(Sub() DoStuff(settings))
Vous pouvez utiliser des expressions lambda
c'est jusqu'à présent la meilleure réponse que j'ai pu trouver, c'est rapide et facile.
la source
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
la source
Parameter
?la source
Un moyen simple d'utiliser lambda comme ça ..
OU vous pourriez même
delegate
utiliserThreadStart
comme ça ...OU en utilisant VS 2019 .NET 4.5+ encore plus propre comme ça ..
la source
Utilisez
ParametrizedThreadStart
.la source
Utilisez ParameterizedThreadStart .
la source
Comme cela a déjà été mentionné dans diverses réponses ici, la
Thread
classe actuellement (4.7.2) fournit plusieurs constructeurs et uneStart
méthode avec des surcharges.Ces constructeurs pertinents pour cette question sont:
et
qui soit prendre un
ThreadStart
délégué ou unParameterizedThreadStart
délégué.Les délégués correspondants ressemblent à ceci:
Donc, comme on peut le voir, le constructeur correct à utiliser semble être celui qui prend un
ParameterizedThreadStart
dé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
Thread
classe seraitou juste
La signature de la méthode correspondante (appelée
Work
dans cet exemple) ressemble à ceci:Ce qui reste est de démarrer le fil. Cela se fait en utilisant soit
ou
Alors
Start()
que démarrerait le thread et passeraitnull
comme données à la méthode,Start(...)
peut être utilisé pour passer n'importe quoi dans laWork
méthode du thread.Il y a cependant un gros problème avec cette approche: tout ce qui est passé dans la
Work
méthode est converti en objet. Cela signifie que dans laWork
méthode, il doit à nouveau être converti en type d'origine, comme dans l'exemple suivant: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 un
InvalidCastException
que vous ne remarquerez probablement pas car il termine simplement le thread.Comme solution, vous vous attendez à obtenir un
ParameterizedThreadStart
délégué générique commeParameterizedThreadStart<T>
oùT
serait le type de données que vous souhaitez transmettre à laWork
mé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:
Avec cette approche, vous commenceriez le fil comme ceci:
Donc, de cette façon, vous évitez simplement de lancer et d'avoir un moyen sûr de fournir des données à un thread ;-)
la source
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
n'est pas possible et ainsi de suite)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 à utiliserTasks<T>
, comme par exempletasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
, voir ma réponse ci-dessous ( stackoverflow.com/a/59777250/7586301 )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
la source
Le
ParameterizedThreadStart
prend 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.
la source
Vous pouvez utiliser un délégué ParametrizedThreadStart :
la source
Vous pouvez utiliser la méthode BackgroundWorker RunWorkerAsync et transmettre votre valeur.
la source
la source
Je propose d'utiliser
Task<T>
au lieu deThread
; il permet plusieurs paramètres et s'exécute très bien.Voici un exemple de travail:
la source
la source