Comment retourner une valeur à partir d'un thread ?
Réponses
Trop de publicités?Ma classe préférée, exécute n'importe quelle méthode sur un autre thread avec seulement 2 lignes de code.
class ThreadedExecuter<T> where T : class
{
public delegate void CallBackDelegate(T returnValue);
public delegate T MethodDelegate();
private CallBackDelegate callback;
private MethodDelegate method;
private Thread t;
public ThreadedExecuter(MethodDelegate method, CallBackDelegate callback)
{
this.method = method;
this.callback = callback;
t = new Thread(this.Process);
}
public void Start()
{
t.Start();
}
public void Abort()
{
t.Abort();
callback(null); //can be left out depending on your needs
}
private void Process()
{
T stuffReturned = method();
callback(stuffReturned);
}
}
utilisation
void startthework()
{
ThreadedExecuter<string> executer = new ThreadedExecuter<string>(someLongFunction, longFunctionComplete);
executer.Start();
}
string someLongFunction()
{
while(!workComplete)
WorkWork();
return resultOfWork;
}
void longFunctionComplete(string s)
{
PrintWorkComplete(s);
}
Attention, longFunctionComplete ne s'exécutera PAS sur le même thread que starthework.
Pour les méthodes qui prennent des paramètres, vous pouvez toujours utiliser des fermetures, ou développer la classe.
Voici un exemple simple utilisant un délégué ...
void Main()
{
DoIt d1 = Doer.DoThatThang;
DoIt d2 = Doer.DoThatThang;
IAsyncResult r1 = d1.BeginInvoke( 5, null, null );
IAsyncResult r2 = d2.BeginInvoke( 10, null, null );
Thread.Sleep( 1000 );
var s1 = d1.EndInvoke( r1 );
var s2 = d2.EndInvoke( r2 );
s1.Dump(); // You told me 5
s2.Dump(); // You told me 10
}
public delegate string DoIt( int x );
public class Doer
{
public static string DoThatThang( int x )
{
return "You told me " + x.ToString();
}
}
Il y a une série formidable sur l'enfilage à Threading en C# .
Avec le dernier .NET Framework, il est possible de renvoyer une valeur à partir d'un thread séparé en utilisant une tâche, où la propriété Result bloque le thread appelant jusqu'à la fin de la tâche :
Task<MyClass> task = Task<MyClass>.Factory.StartNew(() =>
{
string s = "my message";
double d = 3.14159;
return new MyClass { Name = s, Number = d };
});
MyClass test = task.Result;
Pour plus de détails, veuillez consulter http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
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 appropriée et sûre pour les threads) et lire à partir de cet emplacement lorsque le thread a terminé son exécution.
Je suis tombé sur ce fil de discussion alors que j'essayais également d'obtenir la valeur de retour d'une méthode qui est exécutée dans un Thread. J'ai pensé que je pourrais poster ma solution qui fonctionne.
Cette solution utilise une classe pour stocker à la fois la méthode à exécuter (indirectement) et stocker la valeur de retour. La classe peut être utilisée pour n'importe quelle fonction et n'importe quel type de retour. Il suffit d'instancier l'objet en utilisant le type de valeur de retour, puis de passer la fonction à appeler via un lambda (ou un délégué).
Mise en œuvre de C# 3.0
public class ThreadedMethod<T>
{
private T mResult;
public T Result
{
get { return mResult; }
private set { mResult = value; }
}
public ThreadedMethod()
{
}
//If supporting .net 3.5
public void ExecuteMethod(Func<T> func)
{
Result = func.Invoke();
}
//If supporting only 2.0 use this and
//comment out the other overload
public void ExecuteMethod(Delegate d)
{
Result = (T)d.DynamicInvoke();
}
}
Pour utiliser ce code, vous pouvez utiliser un Lambda (ou un délégué). Voici l'exemple utilisant les lambdas :
ThreadedMethod<bool> threadedMethod = new ThreadedMethod<bool>();
Thread workerThread = new Thread((unused) =>
threadedMethod.ExecuteMethod(() =>
SomeMethod()));
workerThread.Start();
workerThread.Join();
if (threadedMethod.Result == false)
{
//do something about it...
}
Mise en œuvre de VB.NET 2008
Les utilisateurs de VB.NET 2008 ne peuvent pas utiliser des lambdas avec des méthodes renvoyant des valeurs. Cela affecte le ThreadedMethod
donc nous allons faire ExecuteMethod
retourne la valeur de la fonction. Cela ne fait pas de mal.
Public Class ThreadedMethod(Of T)
Private mResult As T
Public Property Result() As T
Get
Return mResult
End Get
Private Set(ByVal value As T)
mResult = value
End Set
End Property
Sub New()
End Sub
'If supporting .net 3.5'
Function ExecuteMethod(ByVal func As Func(Of T)) As T
Result = func.Invoke()
Return Result
End Function
'If supporting only 2.0 use this and'
'comment out the other overload'
Function ExecuteMethod(ByVal d As [Delegate]) As T
Result = DirectCast(d.DynamicInvoke(), T)
Return Result
End Function
End Class