C# 探秘如何優雅的終止線程

来源:https://www.cnblogs.com/hsiang/archive/2023/03/20/17232227.html
-Advertisement-
Play Games

在剛接觸後臺線程的時候,覺得線程神秘且高深,並且時常有先輩們千叮萬囑:能不用的時候,儘量不要用,千萬不要濫用線程,否則會發生預料不到的結果。在接觸線程一段時間後,感覺線程也不過如此,輕而易舉的就可以創建,所以逐漸大膽起來,項目里隨處可見的都是Task,Thread,async,await等內容。在大... ...


在剛接觸後臺線程的時候,覺得線程神秘且高深,並且時常有先輩們千叮萬囑:能不用的時候,儘量不要用,千萬不要濫用線程,否則會發生預料不到的結果。在接觸線程一段時間後,感覺線程也不過如此,輕而易舉的就可以創建,所以逐漸大膽起來,項目里隨處可見的都是Task,Thread,async,await等內容。在大多情況下,我們只關心線程的創建與啟動,運行,卻並不關心線程的結束或者終止。今天這篇文章,我們就以一些簡單的小例子,簡述如何有效的停止線程,僅供學習分享使用,如有不足之處,還請指正。

 

 

需求說明

現在有一個需求:有一個後臺線程,定時(300ms)輸出一段內容,但不希望它一直運行,所以設置了超時時間(3s),希望在超時結束後,便執行後續的內容。

初始版本

根據需求,開發了第一個版本的代碼,步驟如下:

  1. 定義一個Task。
  2. 在Task內,運行死迴圈,每間隔300毫秒,輸出一段內容。
  3. 設置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,嚮應該被取消的線程發送信號。即線上程內部判斷是否收到取消請求,在外部發起取消請求信號。步驟如下:

  1. 定義一個Task。
  2. 在Task內,當沒有收到取消信號時,每間隔300毫秒,輸出一段內容。
  3. 設置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迴圈的內容是第三方提供的程式,已經封裝為固定模塊,我們無法進行修改,那應該如何才能終止死迴圈呢?如何才能像任務管理器結束進程一樣,結束這一直無休止運行的程式呢?

為瞭解決我們的難題,對程式進行進一步的優化,步驟如下:

  1. 定義一個Task。
  2. 在Task內,註冊線程的Abort方法,在未調用Abort方法時,每間隔300毫秒,輸出一段內容。
  3. 設置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/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 由於年底失業,以及身體上的原因,所以一直懶著,沒有找工作,也沒有背八股文。當然背八股文對於一些原本基礎較好的人來說,是一個回顧記憶的過程,但是對我這種基礎本身就不牢靠的人來說,無異於是一個很痛苦的過程。所以面試前的知識回顧,應該是以理解為主的一個活動。我上大學時,Java語言還是當時比較熱門的 ...
  • 一、技術棧 核心框架:spring boot2、spring cloud、spring cloud alibaba配置中心:nacos註冊中心:nacos負載均衡:Spring Cloud Load balancer服務調用:open feign服務容錯:Alibaba sentinel api網關 ...
  • Redis是一款開源的高性能key-value資料庫,廣泛應用於各種場景。在Redis中,數據類型(type)和編碼(encoding)是非常重要的概念。本篇博客將詳細介紹Redis支持的數據類型以及相應的編碼方式和底層實現原理。 ...
  • 教程簡介 IT寶庫MS項目入門教程 - 從基本概念開始,簡單易學地學習MS項目,包括設置,簡介,入門,創建新計劃,設置資源,為任務分配資源,計劃持續時間成本和時間,跟蹤進度,高級計劃,項目狀態報告。 Microsoft Project 是一個國際上享有盛譽的通用的項目管理工具軟體,凝集了許多成熟的項 ...
  • 本文已收錄至Github,推薦閱讀 👉 Java隨想錄 微信公眾號:Java隨想錄 摘要 空指針異常(NullPointerException)可以說是Java程式員最容易遇到的問題了,影響說大不大,說小也不小。為瞭解決這個問題,Java 8 版本中推出了 Optional 類。Optional ...
  • _pycache__文件夾可以看作該文件夾下文件已被python接管或者說編譯過。 在第一次執行代碼的時候,Python解釋器已經把編譯的位元組碼放在__pycache__文件夾中,這樣以後再次運行的話,如果被調用的模塊未發生改變,那就直接跳過編譯這一步,直接去__pycache__文件夾中去運行相關 ...
  • 目前由於功能比較簡單,沒有進行前後端拆分,主要技術點:SpringBoot、WebSocket、webjars、Vue、Element-UI、axios、jszip,核心壓縮庫是 Thumbnailator 提供壓縮支持。源代碼已經在 碼雲 star 公開。歡迎各位大佬批評。 ...
  • 解讀 Servlet 源碼:GenericServlet,ServletConfig,ServletContext 每博一文案 人活著,就得隨時準備經受磨難。他已經看過一些書,知道不論是普通人還是了不起的人,都要在自己的一生中經歷許多磨難。磨難使人堅強。 人和社會、一切鬥爭的總結局也許都是中庸而已。 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...