Vous renvoyez une valeur depuis le thread?

Réponses:

94

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
}
Brian Gideon
la source
3
Ne serait-il pas lock(value) { value = "Hello world"; }préférable de gérer l'écriture de valeurs de threads multiples?
checksum
4
@checksum: Dans ce cas particulier, cela n'est pas nécessaire car aucune lecture ou écriture valuen'a lieu en même temps. Mais, oui, soyez toujours conscient du moment où un verrou est nécessaire.
Brian Gideon
Fantastique idée! Fonctionne à merveille et devrait être la réponse acceptée.
MerseyViking
34

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' Threadobjet directement. Dans ce cas, vous pouvez utiliser "fermeture" - déclarer la variable et la capturer en utilisant l'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 des délégués et une IAsyncResultvaleur de retour de la 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 la BackgroundWorkerclasse. Dans ce cas, vous pouvez utiliser une variable capturée (comme avec un Threadobjet) ou gérer un 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 la bibliothèque parallèle de tâches et la Taskclasse pour démarrer vos threads. La classe générique Task<TResult>vous permet d'obtenir la valeur de retour de la Resultproprié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/ awaitkeywords pour renvoyer la valeur de la tâche directement au lieu d'obtenir la Resultpropriété:

int result = await Task.Run(() => {
    //Some work...
    return 42; });

Remarque: la méthode, qui contient le code ci-dessus, doit être marquée avec un asyncmot-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.

Igor Bendrup
la source
33

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:

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

Production:

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

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 check Task<T>.Result.

Eric J.
la source
Oui, mais cela ne s'applique qu'à WinForms et WPF.
Henk Holterman
@Henk: Ce n'est pas vrai. Je viens d'écrire une application console simple qui utilise BackgroundWorker juste pour m'assurer :-) J'ai édité mon message avec ce code.
Eric J.
Eric, mettez quelques écritures dans votre code pour voir quand ce qui se passe et sur quoi ThreadId. Il se peut que cela ne se passe pas comme prévu. (Completed s'exécutera avant que Dowork ne soit terminé, et non sur le thread principal). Le Bgw a besoin d'un MessagePump.
Henk Holterman
@Henk: Vous avez à moitié raison. Terminé s'exécute sur le même thread que BackgroundWorker, mais il s'exécute une fois que DoWork est terminé. Voir la sortie dans la réponse modifiée.
Eric J.
2
Il n'y a pas de condition de concurrence, car exactement un thread définit la variable et exactement un thread la lit, et l'ordre exact de jeu par rapport à lire n'a pas d'importance pour l'exécution correcte du code (c'est-à-dire que la condition de fin peut se produire dans le thread principal un peu plus tôt ou plus tard selon l'ordre dans lequel les threads sont planifiés, mais dans tous les cas, vous obtenez toujours un résultat correct).
Eric J.
21

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:

  • Vous pouvez synchroniser une donnée partagée et la définir de manière appropriée.
  • Vous pouvez également renvoyer les données sous une forme de rappel.

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.

Reed Copsey
la source
15

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

usage

    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 acceptent des paramètres, vous pouvez toujours utiliser des fermetures ou développer la classe.

Erik
la source
3
Pas clair pour tout le monde ... stuffReturned ?, resultOfWork, PrintWorkComplete? etc.
Lost_In_Library
14

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 existe une série formidable sur le threading chez Threading en C # .

JP Alioto
la source
9

Utilisez simplement l'approche déléguée.

int val;
Thread thread = new Thread(() => { val = Multiply(1, 2); });
thread.Start();

Maintenant, créez une fonction Multiply qui fonctionnera sur un autre thread:

int Multiply(int x, int y)
{
    return x * y;
}
yogi
la source
3
Pourquoi cette réponse ci-dessous "enregistrez-le dans un fichier texte et récupérez-le"?
Jon
7

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


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

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 ThreadedMethodclasse, nous allons donc faire ExecuteMethodretourner la valeur de la fonction. Cela ne fait aucun 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
Mat
la source
7

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:

  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 d'informations, consultez http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx

user8128167
la source
5

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.

jscharf
la source
5

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:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadWithDataReturnExample
{
    public partial class Form1 : Form
    {
        private Thread thread1 = null;

        public Form1()
        {
            InitializeComponent();

            thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
            Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            thread1.Start();
            //Alternatively, you could pass some object
            //in such as Start(someObject);
            //With apprioriate locking, or protocol where
            //no other threads access the object until
            //an event signals when the thread is complete,
            //any other class with a reference to the object 
            //would be able to access that data.
            //But instead, I'm going to use AsyncCompletedEventArgs 
            //in an event that signals completion
        }

        void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
        {
            if (this.InvokeRequired)
            {//marshal the call if we are not on the GUI thread                
                BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
                  new object[] { sender, e });
            }
            else
            {
                //display error if error occurred
                //if no error occurred, process data
                if (e.Error == null)
                {//then success

                    MessageBox.Show("Worker thread completed successfully");
                    DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
                    MessageBox.Show("Your data my lord: " + someData.someProperty);

                }
                else//error
                {
                    MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
                }
            }
        }

        #region I would actually move all of this into it's own class
            private void threadEntryPoint()
            {
                //do a bunch of stuff

                //when you are done:
                //initialize object with data that you want to return
                DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
                dataYouWantToReturn.someProperty = "more data";

                //signal completion by firing an event
                OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
            }

            /// <summary>
            /// Occurs when processing has finished or an error occurred.
            /// </summary>
            public event AsyncCompletedEventHandler Thread1Completed;
            protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
            {
                //copy locally
                AsyncCompletedEventHandler handler = Thread1Completed;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
        #endregion

    }
}
AaronLS
la source
J'ai corrigé un détail mineur dans votre code. Il semble que vous ayez laissé de côté la thread1_partie sur son câblage de AsyncCompletedEventHandler . Si ma modification était une erreur, aidez-moi à comprendre ce qui se passait là-bas.
jp2code
1
@ jp2code Vous ne pouvez pas faire thread1_Thread1Completed +=parce que thread1_Thread1Completedc'est le nom d'une fonction, vous ne pouvez donc pas le mettre à gauche d'un opérateur d'affectation. Le côté gauche Thread1Completed +=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;
AaronLS
Je le vois maintenant. Je ne sais pas pourquoi je n'ai pas pu voir ce gestionnaire d'événements dans votre #regionsection auparavant. J'ai regardé. Honnête! :)
jp2code
2

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 BeginInvokemé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 via EndInvoke.

Exemple:

static int GetAnswer() {
   return 42;
}

...

Func<int> method = GetAnswer;
var res = method.BeginInvoke(null, null); // provide args as needed
var answer = method.EndInvoke(res);

GetAnswers'exécutera sur un thread de pool de threads et une fois terminé, vous pourrez récupérer la réponse via EndInvokecomme indiqué.

Brian Rasmussen
la source
2

Le BackgroundWorker est agréable lors du développement pour Windows Forms.

Supposons que vous vouliez passer un cours simple dans les deux sens:

class Anything {
    // Number and Text are for instructional purposes only
    public int Number { get; set; }
    public string Text { get; set; }
    // Data can be any object - even another class
    public object Data { get; set; }
}

J'ai rédigé un court cours qui fait ce qui suit:

  • Créer ou effacer une liste
  • Démarrer une boucle
  • En boucle, créez un nouvel élément pour la liste
  • En boucle, créez un fil
  • En boucle, envoyez l'élément en tant que paramètre au thread
  • En boucle, démarrez le fil
  • En boucle, ajoutez un fil à la liste à regarder
  • Après la boucle, rejoignez chaque thread
  • Une fois toutes les jointures terminées, affichez les résultats

Depuis l'intérieur de la routine de thread:

  • Verrouillage d'appel pour qu'un seul thread puisse entrer dans cette routine à la fois (les autres doivent attendre)
  • Publiez des informations sur l'article.
  • Modifiez l'élément.
  • Une fois le thread terminé, les données sont affichées sur la console.

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.

class AnyTask {

    private object m_lock;

    public AnyTask() {
        m_lock = new object();
    }
    // Something to use the delegate
    public event MainDelegate OnUpdate;

    public void Test_Function(int count) {
        var list = new List<Thread>(count);
        for (var i = 0; i < count; i++) {
            var thread = new Thread(new ParameterizedThreadStart(Thread_Task));
            var item = new Anything() {
                Number = i,
                Text = String.Format("Test_Function #{0}", i)
            };
            thread.Start(item);
            list.Add(thread);
        }
        foreach (var thread in list) {
            thread.Join();
        }
    }

    private void MainUpdate(Anything item, bool original) {
        if (OnUpdate != null) {
            OnUpdate(item, original);
        }
    }

    private void Thread_Task(object parameter) {
        lock (m_lock) {
            var item = (Anything)parameter;
            MainUpdate(item, true);
            item.Text = String.Format("{0}; Thread_Task #{1}", item.Text, item.Number);
            item.Number = 0;
            MainUpdate(item, false);
        }
    }

}

Pour tester cela, créez une petite application console et placez-la dans le fichier Program.cs :

// A delegate makes life simpler
delegate void MainDelegate(Anything sender, bool original);

class Program {

    private const int COUNT = 15;
    private static List<Anything> m_list;

    static void Main(string[] args) {
        m_list = new List<Anything>(COUNT);
        var obj = new AnyTask();
        obj.OnUpdate += new MainDelegate(ThreadMessages);
        obj.Test_Function(COUNT);
        Console.WriteLine();
        foreach (var item in m_list) {
            Console.WriteLine("[Complete]:" + item.Text);
        }
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    private static void ThreadMessages(Anything item, bool original) {
        if (original) {
            Console.WriteLine("[main method]:" + item.Text);
        } else {
            m_list.Add(item);
        }
    }

}

Voici une capture d'écran de ce que j'ai obtenu avec ceci:

Sortie de la console

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.

Imports System.Threading

Delegate Sub MainDelegate(sender As Anything, original As Boolean)

Class Main

    Private Const COUNT As Integer = 15
    Private Shared m_list As List(Of Anything)

    Public Shared Sub Main(args As String())
        m_list = New List(Of Anything)(COUNT)
        Dim obj As New AnyTask()
        AddHandler obj.OnUpdate, New MainDelegate(AddressOf ThreadMessages)
        obj.Test_Function(COUNT)
        Console.WriteLine()
        For Each item As Anything In m_list
            Console.WriteLine("[Complete]:" + item.Text)
        Next
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
    End Sub

    Private Shared Sub ThreadMessages(item As Anything, original As Boolean)
        If original Then
            Console.WriteLine("[main method]:" + item.Text)
        Else
            m_list.Add(item)
        End If
    End Sub

End Class

Class AnyTask

    Private m_lock As Object

    Public Sub New()
        m_lock = New Object()
    End Sub
    ' Something to use the delegate
    Public Event OnUpdate As MainDelegate

    Public Sub Test_Function(count As Integer)
        Dim list As New List(Of Thread)(count)
        For i As Int32 = 0 To count - 1
            Dim thread As New Thread(New ParameterizedThreadStart(AddressOf Thread_Task))
            Dim item As New Anything()
            item.Number = i
            item.Text = String.Format("Test_Function #{0}", i)
            thread.Start(item)
            list.Add(thread)
        Next
        For Each thread As Thread In list
            thread.Join()
        Next
    End Sub

    Private Sub MainUpdate(item As Anything, original As Boolean)
        RaiseEvent OnUpdate(item, original)
    End Sub

    Private Sub Thread_Task(parameter As Object)
        SyncLock m_lock
            Dim item As Anything = DirectCast(parameter, Anything)
            MainUpdate(item, True)
            item.Text = [String].Format("{0}; Thread_Task #{1}", item.Text, item.Number)
            item.Number = 0
            MainUpdate(item, False)
        End SyncLock
    End Sub

End Class


Class Anything
    ' Number and Text are for instructional purposes only
    Public Property Number() As Integer
        Get
            Return m_Number
        End Get
        Set(value As Integer)
            m_Number = value
        End Set
    End Property
    Private m_Number As Integer
    Public Property Text() As String
        Get
            Return m_Text
        End Get
        Set(value As String)
            m_Text = value
        End Set
    End Property
    Private m_Text As String
    ' Data can be anything or another class
    Public Property Data() As Object
        Get
            Return m_Data
        End Get
        Set(value As Object)
            m_Data = value
        End Set
    End Property
    Private m_Data As Object
End Class
jp2code
la source
1
class Program
{
    static void Main(string[] args)
    {
        string returnValue = null;
       new Thread(
          () =>
          {
              returnValue =test() ; 
          }).Start();
        Console.WriteLine(returnValue);
        Console.ReadKey();
    }

    public static string test()
    {
        return "Returning From Thread called method";
    }
}
Shyam sundar shah
la source
L'exemple fourni est faux, vous avez de la chance que cela a fonctionné pour vous. Imaginez la situation suivante 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 à la returnValuevariable. En dernier recours, vous pouvez enregistrer une référence de thread var standaloneThread = new Thread(()=> //...);et après cela, la démarrer de manière synchronisée standaloneThread.Start(); standaloneThread.Join();. Mais ce n'est certainement pas la meilleure pratique.
AlexMelw
1

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.

       // create a list of threads
        List<Thread> threads = new List<Thread>();


        //declare the ref params
        bool is1 = false;
        bool is2 = false;

        threads.Add(new Thread(() => myFunction(someVar, ref is1)));
        threads.Add(new Thread(() => myFunction(someVar, ref is2)));

        threads.ForEach(x => x.Start());

        // wait for threads to finish
        threads.ForEach(x => x.Join());

        //check the ref params
        if (!is1)
        {
          //do something
        }

        if (!is2)
        {
           //do somethign else
        }

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:

 bool theirFunction(var someVar){
   return false;
}


 void myFunction(var someVar ref bool result){
  result = theirFunction(myVar);
 }
CodeToad
la source
veuillez expliquer le vote défavorable. J'utilise ce modèle dans mon propre code et cela fonctionne parfaitement bien.
CodeToad
0

Peut utiliser ce code:

 private Object MyThread(Object Data)
      {
        Object response = null;
        Thread newThread = new Thread(() =>
        {
            response = MyFunction(Data);
            //MyFunction Is Function that you Define
        });
        newThread.Start();
        newThread.Join();
        return response;
      }
Ali asghar Fendereski
la source
-1

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:

Setting.Default.ValueToBeSaved;
Setting.Default.Save();

Ensuite, je récupère cette valeur chaque fois que j'en ai besoin.

Patrik
la source