C# 从线程返回值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1314155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Returning a value from thread?
提问by
How do I return a value from a thread?
如何从线程返回值?
回答by Eric J.
I would use the BackgroundWorkerapproach and return the result in e.Result.
我会使用BackgroundWorker方法并在 e.Result 中返回结果。
EDIT:
编辑:
This is commonly associated with WinForms and WPF, but can be used by any type of .NET application. Here's sample code for a console app that uses BackgroundWorker:
这通常与 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);
}
}
}
}
Output:
输出:
Waiting in Main, tid 10
Work Line: 1, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 2, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 3, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 4, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 5, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Completed, tid 6
2014 UPDATE
2014年更新
See @Roger's answer below.
请参阅下面的@Roger 的回答。
https://stackoverflow.com/a/24916747/141172
https://stackoverflow.com/a/24916747/141172
He points out that you can use a Task that returns a Task<T>
, and check Task<T>.Result
.
他指出,您可以使用返回 a 的 TaskTask<T>
并检查Task<T>.Result
。
回答by jscharf
ThreadStart delegates in C# used to start threads have return type 'void'.
C# 中用于启动线程的 ThreadStart 委托具有返回类型“void”。
If you wish to get a 'return value' from a thread, you should write to a shared location (in an appropriate thread-safe manner) and read from that when the thread has completed executing.
如果您希望从线程获得“返回值”,您应该写入共享位置(以适当的线程安全方式)并在线程完成执行时从中读取。
回答by Reed Copsey
A thread isn't a method - you don't normally "return" a value.
线程不是方法 - 通常不会“返回”值。
However, if you're trying to fetch a value back from the results of some processing, you have many options, the two main ones being:
但是,如果您尝试从某些处理的结果中取回一个值,您有很多选择,主要有两个:
- You can synchronize a shared piece of data, and set it appropriately.
- You can also pass the data back in some form of callback.
- 您可以同步共享数据,并对其进行适当设置。
- 您还可以以某种形式的回调将数据传回。
It really depends on how you're creating the thread, and how you want to use it, as well as the language/framework/tools you're using.
这实际上取决于您如何创建线程,以及您想如何使用它,以及您使用的语言/框架/工具。
回答by Brian Rasmussen
Threads do not really have return values. However, if you create a delegate, you can invoke it asynchronously via the BeginInvoke
method. This will execute the method on a thread pool thread. You can get any return value from such as call via EndInvoke
.
线程并没有真正的返回值。但是,如果您创建委托,则可以通过该BeginInvoke
方法异步调用它。这将在线程池线程上执行该方法。您可以通过调用获取任何返回值EndInvoke
。
Example:
例子:
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
will execute on a thread pool thread and when completed you can retrieve the answer via EndInvoke
as shown.
GetAnswer
将在线程池线程上执行,完成后您可以通过EndInvoke
如图所示检索答案。
回答by JP Alioto
Here is a simple example using a delegate ...
这是一个使用委托的简单示例......
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();
}
}
There's a terrific series on threading at Threading in C#.
在Threading in C# 中有一个关于线程的精彩系列。
回答by AaronLS
If you don't want to use a BackgroundWorker, and just use a regular Thread, then you can fire an event to return data like this:
如果您不想使用 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
}
}
回答by AaronLS
My favorite class, runs any method on another thread with just 2 lines of code.
我最喜欢的类,只需 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);
}
}
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);
}
Beware that longFunctionComplete will NOT execute on the same thread as starthework.
请注意 longFunctionComplete 不会在与 startthework 相同的线程上执行。
For methods that take parameters you can always use closures, or expand the class.
对于带参数的方法,你总是可以使用闭包,或者扩展类。
回答by Matt
I came across this thread when also trying to obtain the return value of a method that gets executed within a Thread. I thought I would post my solution that works.
我在尝试获取在线程中执行的方法的返回值时遇到了这个线程。我想我会发布我的解决方案。
This solution uses an class to store both the method to be executed (indirectly) and stores the returning value. The class can be used for any function and any return type. You just instantiate the object using the return value type and then pass the function to call via a lambda (or delegate).
此解决方案使用一个类来存储要执行的方法(间接)并存储返回值。该类可用于任何函数和任何返回类型。您只需使用返回值类型实例化对象,然后通过 lambda(或委托)传递函数以进行调用。
C# 3.0 Implementation
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();
}
}
To use this code you can use a Lambda (or a delegate). Here is the example using lambdas:
要使用此代码,您可以使用 Lambda(或委托)。以下是使用 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...
}
VB.NET 2008 Implementation
VB.NET 2008 实现
Anyone using VB.NET 2008 can't use lambdas with non-value returning methods. This affects the ThreadedMethod
class, so we'll make ExecuteMethod
return the value of the function. This doesn't hurt anything.
任何使用 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
回答by Brian Gideon
One of the easiest ways to get a return value from a thread is to use closures. Create a variable that will hold the return value from the thread and then capture it in a lambda expression. Assign the "return" value to this variable from the worker thread and then once that thread ends you can use it from the parent thread.
从线程获取返回值的最简单方法之一是使用闭包。创建一个变量来保存线程的返回值,然后在 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
}
回答by Shyam sundar shah
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";
}
}