詳解C#如何優(yōu)雅地終止線程
在剛接觸后臺(tái)線程的時(shí)候,覺得線程神秘且高深,并且時(shí)常有先輩們千叮萬囑:能不用的時(shí)候,盡量不要用,千萬不要濫用線程,否則會(huì)發(fā)生預(yù)料不到的結(jié)果。在接觸線程一段時(shí)間后,感覺線程也不過如此,輕而易舉的就可以創(chuàng)建,所以逐漸大膽起來,項(xiàng)目里隨處可見的都是Task,Thread,async,await等內(nèi)容。在大多情況下,我們只關(guān)心線程的創(chuàng)建與啟動(dòng),運(yùn)行,卻并不關(guān)心線程的結(jié)束或者終止。今天這篇文章,我們就以一些簡單的小例子,簡述如何有效的停止線程,僅供學(xué)習(xí)分享使用,如有不足之處,還請指正。
需求說明
現(xiàn)在有一個(gè)需求:有一個(gè)后臺(tái)線程,定時(shí)(300ms)輸出一段內(nèi)容,但不希望它一直運(yùn)行,所以設(shè)置了超時(shí)時(shí)間(3s),希望在超時(shí)結(jié)束后,便執(zhí)行后續(xù)的內(nèi)容。
初始版本
根據(jù)需求,開發(fā)了第一個(gè)版本的代碼,步驟如下:
- 定義一個(gè)Task。
- 在Task內(nèi),運(yùn)行死循環(huán),每間隔300毫秒,輸出一段內(nèi)容。
- 設(shè)置Task的等待超時(shí)時(shí)間,超時(shí)結(jié)束后,運(yùn)行后續(xù)內(nèi)容。
具體代碼如下所示:
namespace DemoTask
{
internal class Program
{
static void Main(string[] args)
{
TestTask();
Console.ReadKey();
}
/// <summary>
/// 測試任務(wù)
/// </summary>
public static void TestTask()
{
Console.WriteLine("程序開始.");
var task = Task.Run(() =>
{
while (true)
{
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}程序正在運(yùn)行...");
Thread.Sleep(300);
}
});
task.Wait(3000);
Console.WriteLine("程序超時(shí)結(jié)束.");
}
}
}信心滿滿的運(yùn)行程序,但是期待的結(jié)果并沒有出現(xiàn),在超時(shí)時(shí)間后,并沒有預(yù)期的停止任務(wù),反而在繼續(xù)運(yùn)行。如下所示:

注意:通過以上程序發(fā)現(xiàn),Wait方法只是等待時(shí)間結(jié)束后不再等待,但是原有任務(wù)并未結(jié)束,而是繼續(xù)運(yùn)行。
進(jìn)階版本
為了解決線程無法結(jié)束的問題,微軟官方給出的方案是采用CancellationTokenSource,向應(yīng)該被取消的線程發(fā)送信號。即在線程內(nèi)部判斷是否收到取消請求,在外部發(fā)起取消請求信號。步驟如下:
- 定義一個(gè)Task。
- 在Task內(nèi),當(dāng)沒有收到取消信號時(shí),每間隔300毫秒,輸出一段內(nèi)容。
- 設(shè)置Task的等待超時(shí)時(shí)間,超時(shí)結(jié)束后,發(fā)起取消信號,并運(yùn)行后續(xù)內(nèi)容。
具體代碼如下所示:
/// <summary>
/// 測試任務(wù)
/// </summary>
public static void TestTask()
{
Console.WriteLine("程序開始.");
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
var task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}程序正在運(yùn)行...");
Thread.Sleep(300);
}
});
bool flag = task.Wait(3000);
if (!flag) {
cts.Cancel();
}
Console.WriteLine("程序超時(shí)結(jié)束.");
}優(yōu)化程序后,運(yùn)行程序如下所示:

注意:經(jīng)過以上程序優(yōu)化后,確實(shí)是如預(yù)想的結(jié)果一致,程序在等待超時(shí)時(shí)間后,停止了運(yùn)行。
最終版本
正常情況下,如果是我們自己開發(fā)的程序,程序到第二個(gè)版本就已經(jīng)解決問題了,但是假如While循環(huán)的內(nèi)容是第三方提供的程序,已經(jīng)封裝為固定模塊,我們無法進(jìn)行修改,那應(yīng)該如何才能終止死循環(huán)呢?如何才能像任務(wù)管理器結(jié)束進(jìn)程一樣,結(jié)束這一直無休止運(yùn)行的程序呢?
為了解決我們的難題,對程序進(jìn)行進(jìn)一步的優(yōu)化,步驟如下:
- 定義一個(gè)Task。
- 在Task內(nèi),注冊線程的Abort方法,在未調(diào)用Abort方法時(shí),每間隔300毫秒,輸出一段內(nèi)容。
- 設(shè)置Task的等待超時(shí)時(shí)間,超時(shí)結(jié)束后,發(fā)起取消信號,并運(yùn)行后續(xù)內(nèi)容。
具體代碼如下所示:
/// <summary>
/// 測試任務(wù)
/// </summary>
public static void TestTask()
{
Console.WriteLine("程序開始.");
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
var task = Task.Run(() =>
{
using (token.Register((Thread.CurrentThread.Abort)))
{
//假設(shè)以下內(nèi)容第3方提供,無法修改
while (true)
{
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}程序正在運(yùn)行...");
Thread.Sleep(300);
}
//以上內(nèi)容第3方提供
}
});
bool flag = task.Wait(3000);
if (!flag)
{
cts.Cancel();
}
Console.WriteLine("程序超時(shí)結(jié)束.");
}優(yōu)化程序后,運(yùn)行程序如下所示:

到此這篇關(guān)于詳解C#如何優(yōu)雅地終止線程的文章就介紹到這了,更多相關(guān)C#終止線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#如何在窗體程序中操作數(shù)據(jù)庫數(shù)據(jù)
這篇文章主要介紹了C#如何在窗體程序中操作數(shù)據(jù)庫數(shù)據(jù),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
詳解C#如何在不同工作簿之間復(fù)制選定單元格區(qū)域
處理Excel文檔時(shí),我們經(jīng)常需要將數(shù)據(jù)整合到一個(gè)工作表以便于我們進(jìn)行管理或數(shù)據(jù)對比。本文將演示如何通過編程方式將選定的單元格區(qū)域從一個(gè)工作簿復(fù)制到另一個(gè)工作簿2023-02-02
C#實(shí)現(xiàn)IDbConnection/IDbCommand等相關(guān)通用數(shù)據(jù)接口
ADO.NET?中的數(shù)據(jù)提供者對象提供了IDbConnection、IDbCommand、IDbDataParameter等通用數(shù)據(jù)接口,本文將利用這些對象實(shí)現(xiàn)一個(gè)通用方法以訪問和操作數(shù)據(jù)庫內(nèi)容,需要的朋友可以參考下2024-04-04
c# 斷點(diǎn)續(xù)傳的實(shí)現(xiàn)
這篇文章主要介紹了c# 斷點(diǎn)續(xù)傳的實(shí)現(xiàn),幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2020-12-12
C#使用IronPython調(diào)用python代碼的實(shí)現(xiàn)示例
本文主要介紹了在C#中使用IronPython調(diào)用Python代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01

