Comment renvoyer une valeur à partir d'un thread?
103
L'un des moyens les plus simples d'obtenir une valeur de retour d'un thread consiste à utiliser des fermetures. Créez une variable qui contiendra la valeur de retour du thread, puis capturez-la dans une expression lambda. Attribuez la valeur «return» à cette variable à partir du thread de travail, puis une fois que ce thread se termine, vous pouvez l'utiliser à partir du thread parent.
void Main()
{
object value = null; // Used to store the return value
var thread = new Thread(
() =>
{
value = "Hello World"; // Publish the return value
});
thread.Start();
thread.Join();
Console.WriteLine(value); // Use the return value here
}
lock(value) { value = "Hello world"; }
préférable de gérer l'écriture de valeurs de threads multiples?value
n'a lieu en même temps. Mais, oui, soyez toujours conscient du moment où un verrou est nécessaire.Cela dépend de la façon dont vous souhaitez créer le thread et de la version .NET disponible:
.NET 2.0+:
A) Vous pouvez créer l'
Thread
objet directement. Dans ce cas, vous pouvez utiliser "fermeture" - déclarer la variable et la capturer en utilisant l'expression lambda:B) Vous pouvez utiliser des délégués et une
IAsyncResult
valeur de retour de laEndInvoke()
méthode:C) Vous pouvez utiliser la
BackgroundWorker
classe. Dans ce cas, vous pouvez utiliser une variable capturée (comme avec unThread
objet) ou gérer unRunWorkerCompleted
événement:.NET 4.0+:
À partir de .NET 4.0, vous pouvez utiliser la bibliothèque parallèle de tâches et la
Task
classe pour démarrer vos threads. La classe génériqueTask<TResult>
vous permet d'obtenir la valeur de retour de laResult
propriété:.NET 4.5+:
À partir de .NET 4.5, vous pouvez également utiliser
async
/await
keywords pour renvoyer la valeur de la tâche directement au lieu d'obtenir laResult
propriété:Remarque: la méthode, qui contient le code ci-dessus, doit être marquée avec un
async
mot-clé.Pour de nombreuses raisons, l'utilisation de la bibliothèque parallèle de tâches est une manière préférable de travailler avec les threads.
la source
J'utiliserais l' approche BackgroundWorker et retournerais le résultat dans e.Result.
ÉDITER:
Ceci est généralement associé à WinForms et WPF, mais peut être utilisé par tout type d'application .NET. Voici un exemple de code pour une application console qui utilise BackgroundWorker:
Production:
MISE À JOUR 2014
Voir la réponse de @ Roger ci-dessous.
https://stackoverflow.com/a/24916747/141172
Il souligne que vous pouvez utiliser une tâche qui renvoie un
Task<T>
, et checkTask<T>.Result
.la source
Un thread n'est pas une méthode - vous ne "retournez" normalement pas de valeur.
Cependant, si vous essayez de récupérer une valeur à partir des résultats de certains traitements, vous avez de nombreuses options, les deux principales étant:
Cela dépend vraiment de la façon dont vous créez le fil, de la manière dont vous souhaitez l'utiliser, ainsi que du langage / du cadre / des outils que vous utilisez.
la source
Ma classe préférée, exécute n'importe quelle méthode sur un autre thread avec seulement 2 lignes de code.
usage
Attention, longFunctionComplete ne s'exécutera PAS sur le même thread que starthework.
Pour les méthodes qui acceptent des paramètres, vous pouvez toujours utiliser des fermetures ou développer la classe.
la source
Voici un exemple simple utilisant un délégué ...
Il existe une série formidable sur le threading chez Threading en C # .
la source
Utilisez simplement l'approche déléguée.
Maintenant, créez une fonction Multiply qui fonctionnera sur un autre thread:
la source
Je suis tombé sur ce fil en essayant également d'obtenir la valeur de retour d'une méthode qui est exécutée dans un thread. J'ai pensé que je publierais ma solution qui fonctionne.
Cette solution utilise une classe pour stocker à la fois la méthode à exécuter (indirectement) et la valeur renvoyée. La classe peut être utilisée pour n'importe quelle fonction et n'importe quel type de retour. Vous instanciez simplement l'objet à l'aide du type de valeur de retour, puis passez la fonction à appeler via un lambda (ou un délégué).
Implémentation C # 3.0
Pour utiliser ce code, vous pouvez utiliser un Lambda (ou un délégué). Voici l'exemple utilisant des lambdas:
Implémentation VB.NET 2008
Toute personne utilisant VB.NET 2008 ne peut pas utiliser lambdas avec des méthodes de retour sans valeur. Cela affecte la
ThreadedMethod
classe, nous allons donc faireExecuteMethod
retourner la valeur de la fonction. Cela ne fait aucun mal.la source
Avec le dernier .NET Framework, il est possible de renvoyer une valeur à partir d'un thread distinct à l'aide d'un Task, où la propriété Result bloque le thread appelant jusqu'à ce que la tâche se termine:
Pour plus d'informations, consultez http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
la source
Les délégués ThreadStart en C # utilisés pour démarrer les threads ont le type de retour 'void'.
Si vous souhaitez obtenir une «valeur de retour» d'un thread, vous devez écrire dans un emplacement partagé (d'une manière thread-safe appropriée) et lire à partir de celui-ci lorsque le thread a terminé son exécution.
la source
Si vous ne souhaitez pas utiliser un BackgroundWorker et utilisez simplement un Thread normal, vous pouvez déclencher un événement pour renvoyer des données comme ceci:
la source
thread1_
partie sur son câblage de AsyncCompletedEventHandler . Si ma modification était une erreur, aidez-moi à comprendre ce qui se passait là-bas.thread1_Thread1Completed +=
parce quethread1_Thread1Completed
c'est le nom d'une fonction, vous ne pouvez donc pas le mettre à gauche d'un opérateur d'affectation. Le côté gaucheThread1Completed +=
est utilisé car il s'agit d'un événement, il peut donc apparaître sur le côté gauche de l'opérateur d'affectation pour ajouter des gestionnaires d'événements. Voirpublic event AsyncCompletedEventHandler Thread1Completed;
#region
section auparavant. J'ai regardé. Honnête! :)Les threads n'ont pas vraiment de valeurs de retour. Cependant, si vous créez un délégué, vous pouvez l'invoquer de manière asynchrone via la
BeginInvoke
méthode. Cela exécutera la méthode sur un thread de pool de threads. Vous pouvez obtenir n'importe quelle valeur de retour, telle que l'appel viaEndInvoke
.Exemple:
GetAnswer
s'exécutera sur un thread de pool de threads et une fois terminé, vous pourrez récupérer la réponse viaEndInvoke
comme indiqué.la source
Le BackgroundWorker est agréable lors du développement pour Windows Forms.
Supposons que vous vouliez passer un cours simple dans les deux sens:
J'ai rédigé un court cours qui fait ce qui suit:
Depuis l'intérieur de la routine de thread:
L'ajout d'un délégué peut être utile pour publier vos données directement dans votre thread principal, mais vous devrez peut-être utiliser Invoke si certains des éléments de données ne sont pas thread-safe.
Pour tester cela, créez une petite application console et placez-la dans le fichier Program.cs :
Voici une capture d'écran de ce que j'ai obtenu avec ceci:
J'espère que les autres pourront comprendre ce que j'ai essayé d'expliquer.
J'aime travailler sur les fils et utiliser les délégués. Ils rendent C # très amusant.
Annexe: pour les codeurs VB
Je voulais voir ce qu'impliquait l'écriture du code ci-dessus en tant qu'application console VB. La conversion impliquait quelques choses auxquelles je ne m'attendais pas, je vais donc mettre à jour ce fil ici pour ceux qui veulent savoir comment filer en VB.
la source
la source
test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}
. Dans ce cas, le thread autonome n'aurait pas le temps d'attribuer une nouvelle valeur à lareturnValue
variable. En dernier recours, vous pouvez enregistrer une référence de threadvar standaloneThread = new Thread(()=> //...);
et après cela, la démarrer de manière synchroniséestandaloneThread.Start(); standaloneThread.Join();
. Mais ce n'est certainement pas la meilleure pratique.Une solution simple consiste à passer un paramètre par ref à la fonction qui s'exécute dans le thread et à modifier sa valeur dans le thread.
Si vous ne pouvez pas changer la fonction qui s'exécute dans la bande de roulement, vous pouvez l'envelopper d'une autre fonction:
la source
Peut utiliser ce code:
la source
Je ne suis pas une sorte d'expert en filetage, c'est pourquoi je l'ai fait comme ceci:
J'ai créé un fichier de paramètres et
À l'intérieur du nouveau fil:
Ensuite, je récupère cette valeur chaque fois que j'en ai besoin.
la source