1、通過實體類來傳遞(可以傳遞多個引數與獲取返回值),demo如下:
需要線上程中呼叫的函式:
1 2 3 4 5 6 7 8 9 10 11 |
namespace ThreadParameterDemo { public class FunctionClass { public static string TestFunction(string name, int age) { //內部處理省略 return name + " 的年齡是:" + age; } } } |
通過實體來來封裝:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
namespace ThreadParameterDemo { /// /// 過渡類 /// 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); } } } |
呼叫:
1 2 3 4 5 6 7 8 9 |
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推薦:多執行緒方法呼叫提供引數的最好辦法是將目標方法包裹在類中,併為該類定義欄位,這些欄位將被用作新執行緒的引數。
- 這種方法的優點是,任何時候想要啟動新執行緒,都可以建立類的新例項,該例項帶有自身的引數。
- BackgroundWorker 類
- ThreadStart中的函式是沒有返回值和引數的
2、非同步呼叫中的引數和返回值
能完美解決引數和返回值的是使用非同步呼叫的方式。非同步呼叫和Thread相比,一個最大的劣勢是不能控制其優先順序。
具體程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
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); } |
簡化:
1 2 3 4 5 6 7 8 9 10 11 |
public Func 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,可以從工具上直接拖到應用程式:
1 |
BackgroundWorker backgroundWorker1 = new BackgroundWorker(); |
為了開始在後臺操作,必須呼叫BackgroundWorker的RunWorkerAsync()方法,當呼叫此方時,BackgroundWorker 通過觸發DoWork 事件,開始執行後臺操作,DoWork 事件的程式碼是在另一個執行緒裡執行的。
當後臺操作完成以後,無論是completed 還是cancelled,則RunWorkerCompleted 事件被觸發,通過此方法可以將後臺操作的完成結果反饋給使用者。
另外,通過RunWorkerCompletedEventArgs例項的Cancelled 屬性,以判斷是否是Cancel操作使得後臺操作終止。
具體demo如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
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類新增,測試函式如下:
1 2 3 4 |
public static void TestFunction2(string name, int age) { //內部處理省略 } |
呼叫如下:
1 2 3 4 5 6 7 8 |
private void Form1_Load(object sender, EventArgs e) { Thread t1 = new Thread(new ThreadStart(delegate { FunctionClass.TestFunction2("eee", 5); })); t1.Start(); } |
小注:
如果通過WCF來呼叫的話,應該把起執行緒的函式放到服務端,如果放到客戶端,很容易因為WCF客戶端的時間限制,造成造成主程式的莫名崩潰。
崩潰的原因主要是客戶端wcf響應時間是有限制。