C# 多線程參數傳遞

一、經過實體類來傳遞(可以傳遞多個參數與獲取返回值),demo例如如下:html

需要在線程中調用的函數:數據庫

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推薦多線程方法調用提供參數的最好辦法是將目標方法包裹在類中,併爲該類定義字段,這些字段將被用做新線程的參數。async

 

這樣的方法的長處是,不論何時想要啓動新線程。都可以建立類的新實例,該實例帶有自身的參數。函數

        BackgroundWorker 類工具

ThreadStart中的函數是沒有返回值和參數的post

二、異步調用中的參數和返回值
能完美解決參數和返回值的是使用異步調用的方式。異步調用和Thread相比,一個最大的劣勢是不能控制其優先級。

 

詳細代碼例如如下:this

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

小注:spa

經過這樣的方式生成新線程是運行在後臺的(background),優先級爲normal


三、使用 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:點擊打開連接

參考文章:點擊打開連接

四、假設不如返回值的時候。應該怎麼優雅的寫呢?匿名函數啊偷笑

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響應時間是有限制。

相關文章
相關標籤/搜索