Comment retourner une valeur à partir d'un thread ?
Réponses
Trop de publicités?L'une des façons les plus simples d'obtenir une valeur de retour d'un thread est d'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 de retour à cette variable à partir du fil de travail et une fois que ce fil se termine, vous pouvez l'utiliser à partir du fil 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
}
Cela dépend de la manière dont vous voulez créer le fil et de la version .NET disponible :
.NET 2.0+ :
A) Vous pouvez créer le Thread
directement l'objet. Dans ce cas, vous pouvez utiliser la "fermeture" - déclarer une variable et la capturer en utilisant une expression lambda :
object result = null;
Thread thread = new System.Threading.Thread(() => {
//Some work...
result = 42; });
thread.Start();
thread.Join();
Console.WriteLine(result);
B) Vous pouvez utiliser les délégués et IAsyncResult
et la valeur de retour de EndInvoke()
méthode :
delegate object MyFunc();
...
MyFunc x = new MyFunc(() => {
//Some work...
return 42; });
IAsyncResult asyncResult = x.BeginInvoke(null, null);
object result = x.EndInvoke(asyncResult);
C) Vous pouvez utiliser BackgroundWorker
la classe. Dans ce cas, vous pourriez utiliser une variable capturée (comme avec Thread
) ou manipuler RunWorkerCompleted
événement :
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
//Some work...
e.Result = 42;
};
worker.RunWorkerCompleted += (s, e) => {
//e.Result "returned" from thread
Console.WriteLine(e.Result);
};
worker.RunWorkerAsync();
.NET 4.0+ :
À partir de .NET 4.0, vous pouvez utiliser Bibliothèque parallèle des tâches y Task
classe pour commencer vos fils. Classe générique Task<TResult>
vous permet d'obtenir la valeur de retour de Result
propriété :
//Main thread will be blocked until task thread finishes
//(because of obtaining the value of the Result property)
int result = Task.Factory.StartNew(() => {
//Some work...
return 42;}).Result;
.NET 4.5+ :
À partir de .NET 4.5, vous pouvez également utiliser async
/ await
pour retourner la valeur de la tâche directement au lieu d'obtenir la valeur de la tâche. Result
propriété :
int result = await Task.Run(() => {
//Some work...
return 42; });
Note : la méthode, qui contient le code ci-dessus, doit être marquée avec le symbole async
mot-clé.
Pour de nombreuses raisons, l'utilisation de la bibliothèque parallèle des tâches est la meilleure façon de travailler avec les threads.
J'utiliserais le Travailleur d'arrière-plan et renvoyer le résultat dans e.Result.
EDITAR:
Cette fonction est généralement associée à WinForms et WPF, mais elle peut être utilisée par tout type d'application .NET. Voici un exemple de code pour une application console qui utilise BackgroundWorker :
using System;
using System.Threading;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
namespace BGWorker
{
class Program
{
static bool done = false;
static void Main(string[] args)
{
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
bg.RunWorkerAsync();
while (!done)
{
Console.WriteLine("Waiting in Main, tid " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(100);
}
}
static void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Completed, tid " + Thread.CurrentThread.ManagedThreadId);
done = true;
}
static void bg_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Work Line: " + i + ", tid " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
}
}
}
}
Sortie :
Waiting in Main, tid 10
Work Line: 1, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 2, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 3, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 4, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 5, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Completed, tid 6
2014 UPDATE
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 vérifier Task<T>.Result
.
Un fil n'est pas une méthode - normalement, on ne "renvoie" pas une valeur.
Toutefois, si vous essayez de récupérer une valeur à partir des résultats d'un traitement, vous disposez de nombreuses options, les deux principales étant les suivantes :
- Vous pouvez synchroniser un élément de données partagé et le définir de manière appropriée.
- Vous pouvez également renvoyer les données dans une sorte de rappel.
Cela dépend vraiment de la façon dont vous créez le fil, de l'usage que vous voulez en faire, ainsi que du langage/du cadre/des outils que vous utilisez.
- Réponses précédentes
- Plus de réponses