C#筆記19:多線(xiàn)程之線(xiàn)程啟動(dòng)、參數、返回值
本章概要:
1:如何新起線(xiàn)程
2:Thread傳參數及取得返回值
3:IsBackground
4:異步調用中的參數和返回值
新起一個(gè)線(xiàn)程的方法,可以使用Thread,BackgroundWorker ,ThreadPool,控件.BeginInvoke,委托.BeginInvoke,Timer。
創(chuàng )建多線(xiàn)程處理應用程序的最可靠方法是使用 BackgroundWorker 組件。但是,當你需要對線(xiàn)程進(jìn)行精細控制的時(shí)候,就需要Thread??傮w來(lái)說(shuō),各種方法各有各的優(yōu)點(diǎn),在這里不做細說(shuō)。
備注:嚴格意義上,異步不是新線(xiàn)程。
Thread的有兩個(gè)構造函數,其中一個(gè)使用參數是ThreadStart,說(shuō)明該線(xiàn)程在構造函數中不能帶入參數。還有一個(gè)ParameterizedThreadStart,則可以為你的線(xiàn)程傳入參數。還有一個(gè)方法是為你的線(xiàn)程方法提供一個(gè)包裹類(lèi),這也可以解決返回值的問(wèn)題。不過(guò),這種方法在我看來(lái)是最丑陋的寫(xiě)法(參考http://msdn.microsoft.com/zh-cn/library/wkays279.aspx)。
大部分情況下,一個(gè)優(yōu)良的寫(xiě)法是使用匿名函數,如下:
int arg1 = 10; string arg2 = "argument temp"; Thread t1 = new Thread(new ThreadStart(delegate { MessageBox.Show(arg1.ToString() + arg2); }));
以上的寫(xiě)法,仍然無(wú)法解決返回值的問(wèn)題。如果要獲取返回值的,則使用委托或包裹類(lèi)等其它方法。但以上方法解決了參數的問(wèn)題。
必須注意IsBackground的問(wèn)題,如果IsBackground為false的,則Windows程序在退出的時(shí)候,不會(huì )為你自動(dòng)退出該線(xiàn)程。也就是實(shí)際上你的應用程序未結束。
能完美解決參數和返回值的是使用異步調用的方式。異步調用和Thread相比,一個(gè)最大的劣勢是不能控制其優(yōu)先級。
首先,看代碼:
代碼段1:
public delegate string FuncHandle(int data1, int data2); FuncHandle fh ; private void BT_Temp_Click(object sender, RoutedEventArgs e) { fh = new FuncHandle(this.Foo); AsyncCallback callback = new AsyncCallback(this.AsyncCallbackImpl); fh.BeginInvoke(1, 3, callback, null); } public void AsyncCallbackImpl(IAsyncResult ar) { string re = fh.EndInvoke(ar); MessageBox.Show(" " + ar.AsyncState); } string Foo(int data1, int data2) { return " " + data1 + data2; }
在異步調用中,如果想在異步的回調函數中,得到異步函數的返回值(如上面代碼中的Foo函數的string返回值),則必須要在回調函數中使用EndInvoke(關(guān)于EndInvoke會(huì )在下文描述)。在上面的例子是如下這句。
string re = fh.EndInvoke(ar);
但是,有的時(shí)候fh并不見(jiàn)得是個(gè)類(lèi)變量,這個(gè)時(shí)候,就需要我們將EndInvoke的執行主體由BeginInvoke傳遞進(jìn)去??葱薷倪^(guò)后的代碼片段。
代碼段2:
public delegate string FuncHandle(int data1, int data2); private void BT_Temp_Click(object sender, RoutedEventArgs e) { FuncHandle fh = new FuncHandle(this.Foo); AsyncCallback callback = new AsyncCallback(this.AsyncCallbackImpl); fh.BeginInvoke(1, 3, callback, fh); } public void AsyncCallbackImpl(IAsyncResult ar) { FuncHandle dl = ar.AsyncState as FuncHandle; string re = dl.EndInvoke(ar); MessageBox.Show(" " + ar.AsyncState); } string Foo(int data1, int data2) { return "" + data1 + data2; }
通過(guò)舉一反三,其實(shí)BeginInvoke的最后一個(gè)參數,可以是任何對象,看具體的應用場(chǎng)景即可。
下面再介紹一下EndInvoke。EndInvoke在回調函數中,用于承載執行的主體函數的返回值。在另外一個(gè)情況下,即上面的代碼片段一個(gè)簡(jiǎn)化版本,如下:
代碼段3:
public delegate string FuncHandle(int data1, int data2); private void BT_Temp_Click(object sender, RoutedEventArgs e) { FuncHandle fh = new FuncHandle(this.Foo); IAsyncResult ar = fh.BeginInvoke(1, 3, null, fh); string re = fh.EndInvoke(ar); MessageBox.Show(re); } string Foo(int data1, int data2) { return "" + data1 + data2; }
我們可以看到,在這個(gè)代碼片段中,我們根本沒(méi)有使用回調函數,那么,我們就需要通過(guò)EndInvoke來(lái)阻滯主線(xiàn)程,使得返回函數主體的返回值。
再多說(shuō)一點(diǎn),調用了 BeginInvoke 后,可以:
1.進(jìn)行某些操作,然后調用 EndInvoke 一直阻塞到調用完成。如上文的最后一個(gè)代碼片段。
2.使用 IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,使用它的 WaitOne 方法將執行一直阻塞到發(fā)出 WaitHandle 信號,然后調用EndInvoke。這里主要是主程序等待異步方法,等待異步方法的結果。見(jiàn)代碼段4。
3.輪詢(xún)由 BeginInvoke 返回的 IAsyncResult,IAsyncResult.IsCompeted確定異步調用何時(shí)完成,然后調用 EndInvoke。
4.將用于回調方法的委托傳遞給 BeginInvoke。該方法在異步調用完成后在 ThreadPool 線(xiàn)程上執行,它可以調用 EndInvoke。這是在強制裝換回調函數里面IAsyncResult.AsyncState(BeginInvoke方法的最后一個(gè)參數)成委托,然后用委托執行EndInvoke。即如上代碼片段2。
代碼段4:
public delegate string FuncHandle(int data1, int data2); string _sTemp = string.Empty; private void BT_Temp_Click(object sender, RoutedEventArgs e) { FuncHandle fh = new FuncHandle(this.Foo); AsyncCallback callback = new AsyncCallback(this.AsyncCallbackImpl); IAsyncResult ar = fh.BeginInvoke(1, 3, null, null); WaitHandle waitHandle = ar.AsyncWaitHandle; waitHandle.WaitOne(); MessageBox.Show(_sTemp); } string Foo(int data1, int data2) { Thread.Sleep(3000); string re = "" + data1 + data2; _sTemp = re; return re; }
1.You are developing an application to perform mathematical calculations. You develop a class named
CalculationValues. You write a procedure named PerformCalculation that operates on an instance of the class. You
need to ensure that the user interface of the application continues to respond while calculations are being
performed. You need to write a code segment that calls the PerformCalculation procedure to achieve this goal.
Which code segment should you use?
A. private void PerformCalculation() {...}
private void DoWork()
{ CalculationValues myValues = new CalculationValues();
Thread newThread = new Thread( new ThreadStart(PerformCalculation));
newThread.Start(myValues);}
B. private void PerformCalculation() {...}
private void DoWork()
{ CalculationValues myValues = new CalculationValues();
ThreadStart delStart = new ThreadStart(PerformCalculation);
Thread newThread = new Thread(delStart);
if (newThread.IsAlive) {newThread.Start(myValues);}}
C. private void PerformCalculation (CalculationValues values) {...}
private void DoWork()
{ CalculationValues myValues = new CalculationValues();
Application.DoEvents(); PerformCalculation(myValues);
Application.DoEvents();}
D. private void PerformCalculation(object values) {...}
private void DoWork()
{ CalculationValues myValues = new CalculationValues();
Thread newThread = new Thread( new ParameterizedThreadStart(PerformCalculation));
newThread.Start(myValues);}
Answer: D
2.You are developing an application that will perform mathematical calculations. You need to ensure that the
application is able to perform multiple calculations simultaneously. What should you do?
A. Set the IdealProcessor property of the ProcessThread object.
B. Set the ProcessorAffinity property of the ProcessThread object.
C. For each calculation, call the QueueUserWorkItem method of the ThreadPool class.
D. Set the Process.GetCurrentProcess().BasePriority property to High.
Answer: C
3.You are developing an application that will perform mathematical calculations. You need to ensure that the
application is able to perform multiple calculations simultaneously. What should you do?
A. Set the IdealProcessor property of the ProcessThread object.
B. Set the ProcessorAffinity property of the ProcessThread object.
C. For each calculation, call the QueueUserWorkItem method of the ThreadPool class.
D. Set the Process.GetCurrentProcess().BasePriority property to High.
Answer: C
4.Your application uses two threads, named threadOne and threadTwo. You need to modify the code to prevent the execution of threadOne until threadTwo completes execution.
What should you do?
A. Configure threadOne to run at a lower priority.
B. Configure threadTwo to run at a higher priority.
C. Use a WaitCallback delegate to synchronize the threads.
D. Call the Sleep method of threadOne.
E. Call the SpinLock method of threadOne.
Answer: C
| NET C# 入門(mén)級 | .NET C# 專(zhuān)業(yè)級 | .NET 架構級 | BS系統專(zhuān)業(yè)級 | BS系統安全 |
| 1.開(kāi)篇及C#程序、解決方案的結構 2.源碼管理之TFS入門(mén) 3.打老鼠初級 …… 21.CMS之主要功能實(shí)現 22.進(jìn)程和線(xiàn)程基礎 23.類(lèi)型轉換 24.算法基礎 25.初級課程之剩余知識點(diǎn) | 1.消滅打老鼠游戲中的自定義委托 2.垃圾回收 3.Dispose模式 …… 16.異常使用指導 17.最常用的重構指導 18.Debug和IDE的進(jìn)階 19.Resharper的使用 20.ILSPY的使用 | 1.Socket入門(mén) 2.打造打老鼠游戲網(wǎng)絡(luò )版 3.WCF入門(mén) …… 10.依賴(lài)注入 11.萬(wàn)物兼可測試 12.軟件指標之覆蓋率計算 13.軟件指標之代碼行 14.軟件指標之圈復雜度、嵌套深度 | 1.HTML 2.WebForm原理 3.CSS必知必會(huì ) …… 19.讓瀏覽器緩存Shop 20.Asp.net的生命周期 21.Asp.net網(wǎng)站的發(fā)布以及調試晉級 22.BS程序的本質(zhì) 23.壓力測試我們的Shop | 1.Fiddler必知必會(huì ) 2.IE開(kāi)發(fā)者工具必知必會(huì ) 3.跨站腳本防范 4.權限欺騙防范 5.參數越界防范 6.會(huì )話(huà)劫持防范 7.CSRF防范 8.盜鏈防范 9.靜態(tài)文件的保護 |
聯(lián)系客服