Bri*_*eon 92
从线程获取返回值的最简单方法之一是使用闭包.创建一个变量,该变量将保存线程的返回值,然后在lambda表达式中捕获它.从工作线程为此变量分配"return"值,然后一旦该线程结束,您就可以从父线程使用它.
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
}
Run Code Online (Sandbox Code Playgroud)
Eri*_* J. 33
我将使用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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
2014年更新
请参阅下面的@Roger的答案.
他指出你可以使用一个返回a的任务Task<T>
,然后检查Task<T>.Result
.
Igo*_*rup 29
这取决于你想如何创建线程和可用的.NET版本:
.NET 2.0+:
A)您可以Thread
直接创建对象.在这种情况下,您可以使用"closure" - 声明变量并使用lambda-expression捕获它:
object result = null;
Thread thread = new System.Threading.Thread(() => {
//Some work...
result = 42; });
thread.Start();
thread.Join();
Console.WriteLine(result);
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
.NET 4.0+:
从.NET 4.0开始,您可以使用Task Parallel Library和Task
类来启动线程.通用类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;
Run Code Online (Sandbox Code Playgroud)
.NET 4.5+:
从.NET 4.5开始,您还可以使用async
/ await
keywords直接从task返回值,而不是获取Result
属性:
int result = await Task.Run(() => {
//Some work...
return 42; });
Run Code Online (Sandbox Code Playgroud)
注意:方法,其中包含上面的代码应标记为async
关键字.
由于许多原因,使用任务并行库是使用线程的首选方法.
Ree*_*sey 21
线程不是方法 - 您通常不会"返回"值.
但是,如果您尝试从某些处理的结果中获取值,则有许多选项,两个主要选项是:
这实际上取决于您创建线程的方式,以及您希望如何使用它,以及您正在使用的语言/框架/工具.
JP *_*oto 14
这是一个使用委托的简单示例......
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();
}
}
Run Code Online (Sandbox Code Playgroud)
在C#中的线程处有一个很棒的线程系列.
小智 13
我最喜欢的类,只用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);
}
}
Run Code Online (Sandbox Code Playgroud)
用法
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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,longFunctionComplete不会在与starthework相同的线程上执行.
对于采用参数的方法,您始终可以使用闭包,或者扩展类.
我在尝试获取在Thread中执行的方法的返回值时遇到了这个线程.我以为我会发布有效的解决方案.
此解决方案使用类来存储要执行的方法(间接)并存储返回值.该类可用于任何函数和任何返回类型.您只需使用返回值类型实例化对象,然后传递函数以通过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();
}
}
Run Code Online (Sandbox Code Playgroud)
要使用此代码,您可以使用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...
}
Run Code Online (Sandbox Code Playgroud)
VB.NET 2008实现
使用VB.NET 2008的任何人都不能将lambdas与非值返回方法一起使用.这会影响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
Run Code Online (Sandbox Code Playgroud)
使用最新的.NET Framework,可以使用Task从单独的线程返回值,其中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;
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
用于启动线程的C#中的ThreadStart委托的返回类型为“ void”。
如果希望从线程中获取“返回值”,则应(以适当的线程安全方式)写入共享位置,并在线程完成执行后从该位置读取。
如果您不想使用BackgroundWorker,只使用常规Thread,那么您可以触发事件以返回如下数据:
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
}
}
Run Code Online (Sandbox Code Playgroud)
只需使用委托方法。
int val;
Thread thread = new Thread(() => { val = Multiply(1, 2); });
thread.Start();
Run Code Online (Sandbox Code Playgroud)
现在,使Multiply函数可以在另一个线程上运行:
int Multiply(int x, int y)
{
return x * y;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
164939 次 |
最近记录: |