在剛接觸后臺執行緒的時候,覺得執行緒神秘且高深,并且時常有先輩們千叮萬囑:能不用的時候,盡量不要用,千萬不要濫用執行緒,否則會發生預料不到的結果,在接觸執行緒一段時間后,感覺執行緒也不過如此,輕而易舉的就可以創建,所以逐漸大膽起來,專案里隨處可見的都是Task,Thread,async,await等內容,在大多情況下,我們只關心執行緒的創建與啟動,運行,卻并不關心執行緒的結束或者終止,今天這篇文章,我們就以一些簡單的小例子,簡述如何有效的停止執行緒,僅供學習分享使用,如有不足之處,還請指正,
需求說明
現在有一個需求:有一個后臺執行緒,定時(300ms)輸出一段內容,但不希望它一直運行,所以設定了超時時間(3s),希望在超時結束后,便執行后續的內容,
初始版本
根據需求,開發了第一個版本的代碼,步驟如下:
- 定義一個Task,
- 在Task內,運行死回圈,每間隔300毫秒,輸出一段內容,
- 設定Task的等待超時時間,超時結束后,運行后續內容,
具體代碼如下所示:
1 namespace DemoTask 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 TestTask(); 8 Console.ReadKey(); 9 } 10 11 /// <summary> 12 /// 測驗任務 13 /// </summary> 14 public static void TestTask() 15 { 16 Console.WriteLine("程式開始."); 17 var task = Task.Run(() => 18 { 19 while (true) 20 { 21 Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}程式正在運行..."); 22 Thread.Sleep(300); 23 } 24 }); 25 task.Wait(3000); 26 Console.WriteLine("程式超時結束."); 27 } 28 } 29 }
信心滿滿的運行程式,但是期待的結果并沒有出現,在超時時間后,并沒有預期的停止任務,反而在繼續運行,如下所示:
注意:通過以上程式發現,Wait方法只是等待時間結束后不再等待,但是原有任務并未結束,而是繼續運行,
進階版本
為了解決執行緒無法結束的問題,微軟官方給出的方案是采用CancellationTokenSource,向應該被取消的執行緒發送信號,即在執行緒內部判斷是否收到取消請求,在外部發起取消請求信號,步驟如下:
- 定義一個Task,
- 在Task內,當沒有收到取消信號時,每間隔300毫秒,輸出一段內容,
- 設定Task的等待超時時間,超時結束后,發起取消信號,并運行后續內容,
具體代碼如下所示:
1 /// <summary> 2 /// 測驗任務 3 /// </summary> 4 public static void TestTask() 5 { 6 Console.WriteLine("程式開始."); 7 CancellationTokenSource cts = new CancellationTokenSource(); 8 CancellationToken token = cts.Token; 9 var task = Task.Run(() => 10 { 11 while (!token.IsCancellationRequested) 12 { 13 Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}程式正在運行..."); 14 Thread.Sleep(300); 15 } 16 }); 17 bool flag = task.Wait(3000); 18 if (!flag) { 19 cts.Cancel(); 20 } 21 Console.WriteLine("程式超時結束."); 22 }
優化程式后,運行程式如下所示:
注意:經過以上程式優化后,確實是如預想的結果一致,程式在等待超時時間后,停止了運行,
最終版本
正常情況下,如果是我們自己開發的程式,程式到第二個版本就已經解決問題了,但是假如While回圈的內容是第三方提供的程式,已經封裝為固定模塊,我們無法進行修改,那應該如何才能終止死回圈呢?如何才能像任務管理器結束行程一樣,結束這一直無休止運行的程式呢?
為了解決我們的難題,對程式進行進一步的優化,步驟如下:
- 定義一個Task,
- 在Task內,注冊執行緒的Abort方法,在未呼叫Abort方法時,每間隔300毫秒,輸出一段內容,
- 設定Task的等待超時時間,超時結束后,發起取消信號,并運行后續內容,
具體代碼如下所示:
1 /// <summary> 2 /// 測驗任務 3 /// </summary> 4 public static void TestTask() 5 { 6 Console.WriteLine("程式開始."); 7 CancellationTokenSource cts = new CancellationTokenSource(); 8 CancellationToken token = cts.Token; 9 var task = Task.Run(() => 10 { 11 using (token.Register((Thread.CurrentThread.Abort))) 12 { 13 //假設以下內容第3方提供,無法修改 14 while (true) 15 { 16 Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}程式正在運行..."); 17 Thread.Sleep(300); 18 } 19 //以上內容第3方提供 20 } 21 }); 22 bool flag = task.Wait(3000); 23 if (!flag) 24 { 25 cts.Cancel(); 26 } 27 Console.WriteLine("程式超時結束."); 28 }
優化程式后,運行程式如下所示:
以上就是我們對后臺服務執行緒的終止問題的探索,解決問題的方式還有很多,希望本篇文章可以拋磚引玉,一起學習,共同進步,
作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文著作權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段宣告,且在文章頁面明顯位置給出原文連接,謝謝,
關注個人公眾號,定時同步更新技術及職場文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/547418.html
標籤:.NET技术
上一篇:ASP.NET做日歷
下一篇:WPF監聽快捷鍵的幾種方式