C# 多线程參数传递
1、通过实体类来传递(能够传递多个參数与获取返回值),demo例如以下:
须要在线程中调用的函数:
namespace ThreadParameterDemo { public class FunctionClass { public static string TestFunction(string name, int age) { //内部处理省略 return name + " 的年龄是:" + age; } } }通过实体来来封装:
namespace ThreadParameterDemo { /// <summary> /// 过渡类 /// </summary> public class TransitionalClass { private string name = string.Empty; private int age; public string acceptResults = string.Empty; public TransitionalClass(string name, int age) { this.name = name; this.age = age; } public void TestFunction() { acceptResults = FunctionClass.TestFunction(this.name, this.age); } } }调用:
private void Form1_Load(object sender, EventArgs e) { //实例化ThreadWithState类。为线程提供參数 TransitionalClass tc = new TransitionalClass(" Jack", 42); // 创建运行任务的线程,并运行 Thread t = new Thread(new ThreadStart(tc.TestFunction)); t.Start(); //获取返回值。通过 tc.acceptResults; }
小注:
必须注意IsBackground的问题。假设IsBackground为false的,则Windows程序在退出的时候,不会为你自己主动退出该线程。也就是实际上你的应用程序未结束。
MSDN推荐:多线程方法调用提供參数的最好办法是将目标方法包裹在类中,并为该类定义字段,这些字段将被用作新线程的參数。
这样的方法的长处是,不论什么时候想要启动新线程。都能够创建类的新实例,该实例带有自身的參数。
ThreadStart中的函数是没有返回值和參数的
2、异步调用中的參数和返回值能完美解决參数和返回值的是使用异步调用的方式。异步调用和Thread相比,一个最大的劣势是不能控制其优先级。
详细代码例如以下:
public delegate string delegateFunction(string name,int age);//托付 delegateFunction df; private void Form1_Load(object sender, EventArgs e) { //指向须要调用的方法 df = new delegateFunction(FunctionClass.TestFunction); string name = "my name";//输入參数 int age = 19; IAsyncResult result = df.BeginInvoke(name,age, null, null); string myResult = df.EndInvoke(result);//用于接收返回值 MessageBox.Show(myResult); }简化:
public Func<string, int, string> df;//托付 private void Form1_Load(object sender, EventArgs e) { //指向须要调用的方法 df += FunctionClass.TestFunction; string name = "my name";//输入參数 int age = 19; IAsyncResult result = df.BeginInvoke(name, age, null, null); string myResult = df.EndInvoke(result);//用于接收返回值 MessageBox.Show(myResult); }
小注:
通过这样的方式生成新线程是运行在后台的(background),优先级为normal
3、使用 BackgroundWorker
多线程返回值最简单方法是:使用 BackgroundWorker 组件来管理线程,在任务完毕时引发事件,然后用事件处理程序处理结果。
小注:
BackgroundWorker 组件用来运行诸如数据库事务、文件下载等耗时的异步操作。
在应用程序中加入一个BackgroundWorker实例,假设用的是VS,能够从工具上直接拖到应用程序:
BackgroundWorker backgroundWorker1 = new BackgroundWorker();为了開始在后台操作,必须调用BackgroundWorker的RunWorkerAsync()方法。当调用此方时,BackgroundWorker 通过触发DoWork 事件,開始运行后台操作。DoWork 事件的代码是在还有一个线程里运行的。
当后台操作完毕以后,不管是completed 还是cancelled,则RunWorkerCompleted 事件被触发。通过此方法能够将后台操作的完毕结果反馈给用户。
另外,通过RunWorkerCompletedEventArgs实例的Cancelled 属性,以推断是否是Cancel操作使得后台操作终止。
详细demo例如以下:
using System; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form2 : Form { public Form2() { InitializeComponent(); } private void Form2_Load(object sender, EventArgs e) { //TransitionalClass tc = new TransitionalClass("xiaoming", 10); //ThreadPool.QueueUserWorkItem(new WaitCallback(TransitionalClass.TestFunction), tc); } private void button1_Click(object sender, EventArgs e) { this.TestArea2(); } private System.ComponentModel.BackgroundWorker BackgroundWorker1 = new System.ComponentModel.BackgroundWorker(); private void TestArea2() { InitializeBackgroundWorker(); AreaClass2 AreaObject2 = new AreaClass2(); AreaObject2.Base = 30; AreaObject2.Height = 40; // Start the asynchronous operation. BackgroundWorker1.RunWorkerAsync(AreaObject2); } private void InitializeBackgroundWorker() { // Attach event handlers to the BackgroundWorker object. BackgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(BackgroundWorker1_DoWork); BackgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted); } private void BackgroundWorker1_DoWork( object sender, System.ComponentModel.DoWorkEventArgs e) { //在运行DoWork 事件时,DoWorkEventArgs 实例的Result 属性,返回值到用户;在RunWorkerCompleted 事件里,RunWorkerCompletedEventArgs 实例的Result 属性接收值; AreaClass2 AreaObject2 = (AreaClass2)e.Argument; // Return the value through the Result property. e.Result = AreaObject2.CalcArea(); } private void BackgroundWorker1_RunWorkerCompleted( object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { // Access the result through the Result property. double Area = (double)e.Result; MessageBox.Show("The area is: " + Area.ToString()); } } }
demo代码来自MSDN:点击打开链接
參考文章:点击打开链接
4、假设不如返回值的时候。应该怎么优雅的写呢?匿名函数啊
FunctionClass类新增,測试函数例如以下:public static void TestFunction2(string name, int age) { //内部处理省略 }调用例如以下:
private void Form1_Load(object sender, EventArgs e) { Thread t1 = new Thread(new ThreadStart(delegate { FunctionClass.TestFunction2("eee", 5); })); t1.Start(); }
小注:
假设通过WCF来调用的话,应该把起线程的函数放到服务端,假设放到client。非常easy由于WCFclient的时间限制,造成造成主程序的莫名崩溃。
崩溃的原因主要是clientwcf响应时间是有限制。