【问题标题】:Returning a value from thread?从线程返回一个值?
【发布时间】:2009-08-21 20:49:43
【问题描述】:

如何从线程返回值?

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    从线程获取返回值的最简单方法之一是使用闭包。创建一个变量来保存线程的返回值,然后在 lambda 表达式中捕获它。从工作线程将“返回”值分配给该变量,然后一旦该线程结束,您就可以从父线程中使用它。

    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"; } 处理多线程值写入不是更好吗?
    • @checksum:在这种特殊情况下,这是不必要的,因为没有同时发生对value 的读取或写入。但是,是的,请始终注意何时需要锁定。
    • 好主意!效果很好,应该是公认的答案。
    【解决方案2】:

    这取决于你想如何创建线程和可用的 .NET 版本:

    .NET 2.0+:

    A) 您可以直接创建Thread 对象。在这种情况下,您可以使用“闭包” - 声明变量并使用 lambda 表达式捕获它:

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

    B) 您可以使用委托和IAsyncResult 并从EndInvoke() 方法返回值:

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

    C) 你可以使用BackgroundWorker 类。在这种情况下,您可以使用捕获的变量(如 Thread 对象)或处理 RunWorkerCompleted 事件:

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

    从 .NET 4.0 开始,您可以使用 Task Parallel LibraryTask 类来启动您的线程。泛型类Task<TResult> 允许您从Result 属性中获取返回值:

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

    从 .NET 4.5 开始,您还可以使用 async/await 关键字直接从任务返回值,而不是获取 Result 属性:

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

    注意:方法,包含上面的代码应该用asynckeyword标记。

    出于多种原因,使用任务并行库是处理线程的首选方式。

    【讨论】:

      【解决方案3】:

      我会使用BackgroundWorker 方法并在 e.Result 中返回结果。

      编辑:

      这通常与 WinForms 和 WPF 相关联,但可以由任何类型的 .NET 应用程序使用。以下是使用 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);
                  }
              }
          }
      }
      

      输出:

      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 年更新

      请参阅下面@Roger 的回答。

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

      他指出您可以使用返回Task&lt;T&gt; 的Task,并检查Task&lt;T&gt;.Result

      【讨论】:

      • 是的,但它只适用于 WinForms 和 WPF。
      • @Henk:不正确。我刚刚编写了一个使用 BackgroundWorker 的简单控制台应用程序,以确保 :-) 使用该代码编辑了我的帖子。
      • Eric,在你的代码中加入一些写行,看看什么时候会发生什么,以及在什么 ThreadId 上。它可能不会如你所愿。 (Completed 将在 Dowork 完成之前运行,而不是在主线程上)。 Bgw 需要一个 MessagePump。
      • @Henk:你说对了一半。 Completed 运行在与 BackgroundWorker 相同的线程上,但它确实在 DoWork 完成后运行。在编辑后的答案中查看输出。
      • 不存在竞争条件,因为只有一个线程设置变量并且只有一个线程读取它,设置与读取的确切顺序与代码的正确执行无关(即终止条件可能会稍早或稍晚地发生在主线程中,具体取决于线程调度的顺序,但无论哪种方式,您仍然可以获得正确的结果。
      【解决方案4】:

      线程不是方法——你通常不会“返回”一个值。

      但是,如果您尝试从某些处理的结果中取回一个值,您有很多选择,其中两个主要是:

      • 您可以同步共享数据,并进行适当的设置。
      • 您还可以通过某种形式的回调将数据传回。

      这实际上取决于您创建线程的方式、您希望如何使用它,以及您使用的语言/框架/工具。

      【讨论】:

        【解决方案5】:

        我最喜欢的类,只需 2 行代码即可在另一个线程上运行任何方法。

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

        用法

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

        请注意 longFunctionComplete 不会与 startthework 在同一线程上执行。

        对于带参数的方法,您始终可以使用闭包,或扩展类。

        【讨论】:

        • 不是每个人都清楚... stuffReturned?, resultOfWork, PrintWorkComplete ?等
        【解决方案6】:

        只需使用委托方法。

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

        现在制作可以在另一个线程上工作的乘法函数:

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

        【讨论】:

        • 为什么下面的答案是“将其保存到文本文件并检索它”?
        【解决方案7】:

        这是一个使用委托的简单示例...

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

        Threading in C# 上有一个很棒的线程系列。

        【讨论】:

          【解决方案8】:

          使用最新的 .NET Framework,可以使用任务从单独的线程返回值,其中 Result 属性会阻塞调用线程,直到任务完成:

            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;
          

          详情请见http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx

          【讨论】:

            【解决方案9】:

            我在尝试获取在线程中执行的方法的返回值时遇到了这个线程。我想我会发布我的解决方案。

            此解决方案使用一个类来存储要(间接)执行的方法并存储返回值。该类可用于任何函数和任何返回类型。您只需使用返回值类型实例化对象,然后通过 lambda(或委托)传递函数以调用。


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

            要使用此代码,您可以使用 Lambda(或委托)。这是使用 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...
            }
            

            VB.NET 2008 实现


            任何使用 VB.NET 2008 的人都不能使用带有非值返回方法的 lambda。这会影响ThreadedMethod 类,因此我们将让ExecuteMethod 返回函数的值。这不会伤害任何东西。

            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
            

            【讨论】:

              【解决方案10】:

              C# 中用于启动线程的 ThreadStart 委托具有返回类型“void”。

              如果您希望从线程获取“返回值”,您应该写入共享位置(以适当的线程安全方式)并在线程完成执行时从该位置读取。

              【讨论】:

                【解决方案11】:

                如果您不想使用 BackgroundWorker,而只是使用常规线程,那么您可以触发事件以返回如下数据:

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

                【讨论】:

                • 我修复了您代码中的一个小细节。看起来您在他的 AsyncCompletedEventHandler 接线中省略了thread1_ 部分。如果我的编辑有误,请帮助我了解那里发生了什么。
                • @jp2code 你不能做thread1_Thread1Completed += 因为thread1_Thread1Completed 是一个函数的名字,所以你不能把它放在赋值运算符的左边。使用左侧Thread1Completed +=,因为这是一个事件,所以它可以出现在赋值运算符的左侧以添加事件处理程序。见public event AsyncCompletedEventHandler Thread1Completed;
                • 我现在看到了。我不知道为什么我之前无法在您的 #region 部分看到该事件处理程序。我看了。诚实的! :)
                【解决方案12】:

                线程实际上没有返回值。但是,如果您创建一个委托,您可以通过 BeginInvoke 方法异步调用它。这将在线程池线程上执行该方法。您可以通过EndInvoke 获取任何返回值,例如调用。

                例子:

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

                GetAnswer 将在线程池线程上执行,完成后您可以通过EndInvoke 检索答案,如图所示。

                【讨论】:

                  【解决方案13】:

                  BackgroundWorker 非常适合为 Windows 窗体进行开发。

                  假设你想来回传递一个简单的类:

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

                  我编写了一个简短的类,它执行以下操作:

                  • 创建或清除列表
                  • 开始循环
                  • 在循环中,为列表创建一个新项目
                  • 在循环中,创建一个线程
                  • 在循环中,将项目作为参数发送到线程
                  • 在循环中,启动线程
                  • 在循环中,将线程添加到要观看的列表中
                  • 循环后,加入每个线程
                  • 所有连接都完成后,显示结果

                  从线程例程内部:

                  • 调用 lock 以便一次只有 1 个线程可以进入此例程(其他线程必须等待)
                  • 发布有关该项目的信息。
                  • 修改项目。
                  • 线程完成后,数据会显示在控制台上。

                  添加delegate 有助于将数据直接发送回主线程,但如果某些数据项不是线程安全的,则可能需要使用Invoke

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

                  要对此进行测试,请创建一个小控制台应用程序,并将其放入 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);
                          }
                      }
                  
                  }
                  

                  这是我得到的截图:

                  我希望其他人能理解我试图解释的内容。

                  我喜欢处理线程和使用委托。它们让 C# 变得很有趣。

                  附录:适用于 VB 编码人员

                  我想看看将上面的代码编写为 VB 控制台应用程序所涉及的内容。转换涉及到一些我没想到的事情,所以我将在此处更新此线程以供那些想知道如何在 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
                  

                  【讨论】:

                    【解决方案14】:

                    可以使用此代码:

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

                    【讨论】:

                      【解决方案15】:
                      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";
                          }
                      }
                      

                      【讨论】:

                      • 提供的示例是错误的,你很幸运它对你有用。想象一下以下情况test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}。在这种情况下,独立线程将没有时间为 returnValue 变量分配新值。作为最后的手段,您可以保存一个线程引用var standaloneThread = new Thread(()=&gt; //...);,然后以同步方式启动它standaloneThread.Start(); standaloneThread.Join();。但这肯定不是最佳做法。
                      【解决方案16】:

                      一个简单的解决方案是通过 ref 将参数传递给正在线程中运行的函数,并在线程中更改其值。

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

                      如果你不能改变正在运行的函数,你可以把它换成另一个函数:

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

                      【讨论】:

                      • 请解释否决票。我在自己的代码中使用了这种模式,并且效果很好。
                      【解决方案17】:
                      class Program
                      {
                          public static void ActionResultPrint(string i)
                          {
                              Console.WriteLine(i);
                          }
                      
                          static void Main(string[] args)
                          {
                              var tl = new List<Thread>();
                      
                              tl.Add(new Thread(() => Run(10, ActionResultPrint)));
                              tl.Add(new Thread(() => Run(20, ActionResultPrint)));
                              tl.ForEach(x => x.Start());
                              tl.ForEach(x => x.Join());
                          }
                      
                          public static void Run(int j, Action<string> action)
                          {
                              string rvalue = string.Empty;
                      
                              for (int i = 0; i <= j; i++)
                              {
                                  Thread.Sleep(100);
                                  rvalue = i.ToString();
                                  Console.WriteLine(rvalue);
                              }
                              action($@"output {j}");
                          }
                      }
                      

                      【讨论】:

                        【解决方案18】:

                        使用线程时,可以通过以下方式传递和返回值:

                        int value = -1;
                          Thread t1 = new Thread(() => { value = compute(a); });
                           t1.Start();
                         if(value!=-1)
                         {...}
                        
                           public int compute(int[] a1)
                            {
                            //...code logic
                                return -1;
                            }
                        

                        【讨论】:

                          【解决方案19】:

                          我不是线程方面的专家,这就是我这样做的原因:

                          我创建了一个设置文件并

                          在新线程内:

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

                          然后我会在需要时获取该值。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-11-06
                            • 2012-02-27
                            相关资源
                            最近更新 更多