Restituendo un valore dal thread?


Risposte:


94

Uno dei modi più semplici per ottenere un valore restituito da un thread è utilizzare le chiusure. Creare una variabile che conterrà il valore restituito dal thread e quindi acquisirlo in un'espressione lambda. Assegna il valore di "ritorno" a questa variabile dal thread di lavoro e quindi una volta che il thread termina puoi usarlo dal thread padre.

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
}

3
Non lock(value) { value = "Hello world"; }sarebbe meglio gestire la scrittura di valori di thread multipli?
checksum

4
@checksum: in questo caso particolare non è necessario perché non valuevengono eseguite letture o scritture contemporaneamente. Ma sì, sii sempre consapevole di quando è necessario un lucchetto.
Brian Gideon,

Idea fantastica! Funziona brillantemente e dovrebbe essere la risposta accettata.
MerseyViking

34

Dipende da come si desidera creare il thread e dalla versione .NET disponibile:

.NET 2.0+:

A) Puoi creare l' Threadoggetto direttamente. In questo caso puoi usare "chiusura" - dichiara la variabile e catturala usando l'espressione lambda:

object result = null;
Thread thread = new System.Threading.Thread(() => { 
    //Some work...
    result = 42; });
thread.Start();
thread.Join();
Console.WriteLine(result);

B) È possibile utilizzare delegati IAsyncResultee valore restituito dal EndInvoke()metodo:

delegate object MyFunc();
...
MyFunc x = new MyFunc(() => { 
    //Some work...
    return 42; });
IAsyncResult asyncResult = x.BeginInvoke(null, null);
object result = x.EndInvoke(asyncResult);

C) Puoi usare BackgroundWorkerclass. In questo caso potresti usare la variabile catturata (come con l' Threadoggetto) o gestire l' RunWorkerCompletedevento:

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+:

A partire da .NET 4.0 è possibile utilizzare Task Parallel Library e la Taskclasse per avviare i thread. La classe generica Task<TResult>ti consente di ottenere il valore restituito dalla Resultproprietà:

//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+:

A partire da .NET 4.5 potresti anche usare async/ awaitkeywords per restituire il valore direttamente dall'attività invece di ottenere la Resultproprietà:

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

Nota: il metodo, che contiene il codice sopra, deve essere contrassegnato con asyncparola chiave.

Per molte ragioni l'utilizzo di Task Parallel Library è un modo preferibile di lavorare con i thread.


33

Vorrei utilizzare l' approccio BackgroundWorker e restituire il risultato in e.Result.

MODIFICARE:

Questo è comunemente associato a WinForms e WPF, ma può essere utilizzato da qualsiasi tipo di applicazione .NET. Ecco un esempio di codice per un'app console che utilizza 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);
            }
        }
    }
}

Produzione:

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

AGGIORNAMENTO 2014

Vedi la risposta di @ Roger di seguito.

https://stackoverflow.com/a/24916747/141172

Sottolinea che puoi usare un'attività che restituisce a Task<T>e controlla Task<T>.Result.


Sì, ma si applica solo a WinForms e WPF.
Henk Holterman

@ Henk: Non è vero. Ho appena scritto una semplice app per console che usa BackgroundWorker solo per assicurarmi :-) Ho modificato il mio post con quel codice.
Eric J.

Eric, inserisci alcune linee di scrittura nel tuo codice per vedere quando cosa succede e su quale ThreadId. Potrebbe non andare come ti aspetti. (Completed verrà eseguito prima che Dowork sia terminato e non nel thread principale). Il Bgw ha bisogno di un MessagePump.
Henk Holterman

@ Henk: hai ragione a metà. Completato viene eseguito sullo stesso thread di BackgroundWorker, ma viene eseguito dopo che DoWork è stato completato. Vedere l'output nella risposta modificata.
Eric J.

2
Non esiste una condizione di competizione, perché esattamente un thread imposta la variabile e esattamente un thread la legge, e l'ordine esatto di set rispetto alla lettura non ha importanza per la corretta esecuzione del codice (cioè la condizione di terminazione potrebbe verificarsi nel thread principale leggermente prima o dopo a seconda dell'ordine in cui sono pianificati i thread, ma in entrambi i casi si ottiene comunque un risultato corretto).
Eric J.

21

Un thread non è un metodo: normalmente non "restituisci" un valore.

Tuttavia, se stai cercando di recuperare un valore dai risultati di alcune elaborazioni, hai molte opzioni, le due principali sono:

  • È possibile sincronizzare un dato condiviso e impostarlo in modo appropriato.
  • Puoi anche ritrasmettere i dati in qualche forma di richiamata.

Dipende davvero da come stai creando il thread e da come vuoi usarlo, così come dal linguaggio / framework / strumenti che stai usando.


15

La mia classe preferita, esegue qualsiasi metodo su un altro thread con solo 2 righe di codice.

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

utilizzo

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

Attenzione che longFunctionComplete NON verrà eseguito sullo stesso thread di starthework.

Per i metodi che accettano parametri puoi sempre usare le chiusure o espandere la classe.


3
Non è chiaro per tutti ... stuffReturned ?, resultOfWork, PrintWorkComplete? ecc.
Lost_In_Library

14

Ecco un semplice esempio che utilizza un delegato ...

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

C'è una serie eccezionale sul threading in Threading in C # .


9

Usa semplicemente l'approccio delegato.

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

Ora crea la funzione Moltiplica che funzionerà su un altro thread:

int Multiply(int x, int y)
{
    return x * y;
}

3
Perché questa risposta di seguito è "salvarla in un file di testo e recuperarla"?
Jon

7

Mi sono imbattuto in questo thread anche quando cercavo di ottenere il valore di ritorno di un metodo che viene eseguito all'interno di un thread. Ho pensato di pubblicare la mia soluzione che funziona.

Questa soluzione utilizza una classe per memorizzare sia il metodo da eseguire (indirettamente) sia per memorizzare il valore restituito. La classe può essere utilizzata per qualsiasi funzione e qualsiasi tipo restituito. È sufficiente creare un'istanza dell'oggetto utilizzando il tipo di valore restituito e quindi passare la funzione da chiamare tramite lambda (o delegato).


Implementazione di 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();
    }
}

Per usare questo codice puoi usare un Lambda (o un delegato). Ecco l'esempio che utilizza lambda:

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

Implementazione di VB.NET 2008


Chiunque utilizzi VB.NET 2008 non può utilizzare lambda con metodi di restituzione senza valore. Ciò influisce sulla ThreadedMethodclasse, quindi ExecuteMethodrestituiremo il valore della funzione. Questo non fa male a niente.

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

7

Con l'ultima versione di .NET Framework, è possibile restituire un valore da un thread separato utilizzando un'attività, in cui la proprietà Result blocca il thread chiamante fino al termine dell'attività:

  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;

Per i dettagli, vedere http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx


5

I delegati ThreadStart in C # usati per avviare i thread hanno il tipo restituito "void".

Se desideri ottenere un "valore di ritorno" da un thread, dovresti scrivere in una posizione condivisa (in un modo appropriato per thread-safe) e leggere da quella quando il thread ha completato l'esecuzione.


5

Se non vuoi usare un BackgroundWorker e usi solo un thread normale, puoi attivare un evento per restituire dati come questo:

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

    }
}

Ho corretto un piccolo dettaglio nel tuo codice. Sembra che tu abbia interrotto la thread1_parte del suo cablaggio di AsyncCompletedEventHandler . Se la mia modifica era sbagliata, aiutami a capire cosa stava succedendo lì.
jp2code

1
@ jp2code Non puoi farlo thread1_Thread1Completed +=perché thread1_Thread1Completedè il nome di una funzione, quindi non puoi metterlo sul lato sinistro di un operatore di assegnazione. Il lato sinistro Thread1Completed +=viene utilizzato perché si tratta di un evento, quindi può essere visualizzato sul lato sinistro dell'operatore di assegnazione per aggiungere gestori di eventi. Vederepublic event AsyncCompletedEventHandler Thread1Completed;
AaronLS

Ora lo vedo. Non so perché non sono riuscito a vedere prima quel gestore di eventi nella tua #regionsezione. Ho guardato. Onesto! :)
jp2code

2

I thread non hanno realmente valori di ritorno. Tuttavia, se crei un delegato, puoi richiamarlo in modo asincrono tramite il BeginInvokemetodo. Questo eseguirà il metodo su un thread del pool di thread. È possibile ottenere qualsiasi valore di ritorno da come call tramite EndInvoke.

Esempio:

static int GetAnswer() {
   return 42;
}

...

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

GetAnswerverrà eseguito su un thread del pool di thread e una volta completato è possibile recuperare la risposta tramite EndInvokecome mostrato.


2

Il BackgroundWorker è bello quando in via di sviluppo per Windows Form.

Supponi di voler passare avanti e indietro una lezione semplice:

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

Ho scritto una breve lezione che fa quanto segue:

  • Crea o cancella un elenco
  • Inizia un ciclo
  • In loop, crea un nuovo elemento per l'elenco
  • Crea un thread in loop
  • In loop, invia l'elemento come parametro al thread
  • In loop, avvia il thread
  • In loop, aggiungi thread all'elenco da guardare
  • Dopo il ciclo, unisci ogni thread
  • Dopo che tutti i join sono stati completati, visualizzare i risultati

Dall'interno della routine thread:

  • Blocco chiamate in modo che solo 1 thread alla volta possa accedere a questa routine (gli altri devono aspettare)
  • Pubblica informazioni sull'articolo.
  • Modifica l'articolo.
  • Al termine del thread, i dati vengono visualizzati sulla console.

L'aggiunta di un delegato può essere utile per inviare nuovamente i dati direttamente al thread principale, ma potrebbe essere necessario utilizzare Invoke se alcuni degli elementi di dati non sono 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);
        }
    }

}

Per verificarlo, crea una piccola applicazione console e inseriscila nel file 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);
        }
    }

}

Ecco uno screenshot di quello che ho ottenuto con questo:

Uscita console

Spero che gli altri possano capire quello che ho cercato di spiegare.

Mi piace lavorare sui thread e usare i delegati. Rendono C # molto divertente.

Appendice: per codificatori VB

Volevo vedere cosa era coinvolto nella scrittura del codice sopra come applicazione console VB. La conversione ha coinvolto alcune cose che non mi aspettavo, quindi aggiornerò questo thread qui per coloro che vogliono sapere come eseguire il thread in 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

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

L'esempio fornito è sbagliato, sei stato fortunato che abbia funzionato per te. Immagina la seguente situazione test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}. In questo caso il thread autonomo non avrebbe il tempo di assegnare un nuovo valore alla returnValuevariabile. Come ultima risorsa, puoi salvare un riferimento al thread var standaloneThread = new Thread(()=> //...);e successivamente avviarlo in modo sincronizzato standaloneThread.Start(); standaloneThread.Join();. Ma questa non è certamente la migliore pratica.
AlexMelw

1

Una soluzione semplice è passare un parametro per ref alla funzione in esecuzione nel thread e modificarne il valore nel 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
        }

Se non puoi modificare la funzione in esecuzione nel battistrada, puoi avvolgerla in un'altra funzione:

 bool theirFunction(var someVar){
   return false;
}


 void myFunction(var someVar ref bool result){
  result = theirFunction(myVar);
 }

si prega di spiegare il voto negativo. Uso questo modello nel mio codice e funziona perfettamente.
CodeToad

0

Può usare questo codice:

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

-1

Non sono un esperto in threading, ecco perché l'ho fatto in questo modo:

Ho creato un file di impostazioni e

All'interno del nuovo thread:

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

Quindi prendo quel valore ogni volta che ne ho bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.