亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C# Task取消暫停的實現(xiàn)

 更新時間:2024年11月29日 11:20:39   作者:語衣  
本文主要介紹了C# Task取消暫停的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

CancellationTokenSource 和 CancellationToken

CancellationTokenSource

CancellationTokenSource是一個用于創(chuàng)建和控制CancellationToken的類。它是觸發(fā)取消操作的關(guān)鍵點,并且提供了觸發(fā)取消操作的方法(如Cancel)和檢查是否已請求取消的屬性(如IsCancellationRequested)。

主要方法

  • Cancel(): 觸發(fā)取消操作。
  • Dispose(): 釋放CancellationTokenSource占用的資源。

主要屬性

  • IsCancellationRequested: 指示是否已請求取消。
  • Token: 獲取與此CancellationTokenSource關(guān)聯(lián)的CancellationToken。

CancellationToken

CancellationToken是一個輕量級的對象,用于在線程之間傳遞取消信號。它本身不執(zhí)行任何取消操作,而是作為取消請求的標(biāo)記。當(dāng)某個操作應(yīng)該被取消時,與該CancellationToken關(guān)聯(lián)的CancellationTokenSource會發(fā)出一個取消信號,然后任何監(jiān)聽這個CancellationToken的代碼都可以響應(yīng)這個取消請求。

主要方法

  • Register(Action callback): 注冊一個回調(diào),當(dāng)取消操作被觸發(fā)時調(diào)用該回調(diào)。
  • ThrowIfCancellationRequested(): 如果已請求取消,則拋出OperationCanceledException異常。

主要屬性

  • IsCancellationRequested: 指示是否已請求取消。

使用示例

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var cts = new CancellationTokenSource();
        var token = cts.Token;

        var task = Task.Run(() => DoWork(token), token);

        // 模擬一段時間后取消操作
        Thread.Sleep(2000);
        cts.Cancel();

        try
        {
            await task; // 如果操作被取消,這里會拋出異常
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Operation was canceled.");
        }
    }

    static void DoWork(CancellationToken token)
    {
        for (int i = 0; i < 10; i++)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Cancellation requested.");
                return;
            }
            Thread.Sleep(500); // 模擬工作
            Console.WriteLine($"Working... {i}");
        }
    }
}

當(dāng)使用 CancellationToken 與 Task.Run 時,有幾個關(guān)鍵點需要注意:

  • 傳遞給 Task.Run 的 CancellationToken:這個 CancellationToken 用于控制 Task.Run 創(chuàng)建的任務(wù)的生命周期。如果取消這個令牌(即調(diào)用 CancellationTokenSource.Cancel()),那么 Task 將接收到一個取消請求,但這并不意味著任務(wù)會立即停止執(zhí)行。任務(wù)中的代碼需要顯式檢查這個取消請求(通常通過調(diào)用 cancellationToken.ThrowIfCancellationRequested() 或檢查 cancellationToken.IsCancellationRequested 屬性)并據(jù)此決定是否停止執(zhí)行。

  • 傳遞給 DoWork 方法的 CancellationToken:這個 CancellationToken 是作為參數(shù)傳遞給 DoWork 方法的。在 DoWork 方法內(nèi)部,你可以根據(jù)這個令牌的狀態(tài)來決定是否繼續(xù)執(zhí)行。如果檢測到取消請求(IsCancellationRequested 為 true),你可以提前退出方法或執(zhí)行清理操作。但是,僅僅設(shè)置這個令牌的取消狀態(tài)并不會自動停止 DoWork 方法的執(zhí)行;你需要編寫相應(yīng)的邏輯來處理取消請求。

  • 任務(wù)的取消:即使你取消了 CancellationToken,Task 對象本身也不會立即變?yōu)?ldquo;已取消”狀態(tài)。相反,它會變?yōu)?ldquo;已取消請求”狀態(tài),這意味著已經(jīng)請求取消該任務(wù),但任務(wù)可能仍在執(zhí)行中。只有當(dāng)任務(wù)中的代碼顯式檢查并響應(yīng)取消請求時,任務(wù)才會停止執(zhí)行并最終變?yōu)?ldquo;已取消”狀態(tài)。

  • 異常處理:如果在任務(wù)中檢測到取消請求并調(diào)用了 cancellationToken.ThrowIfCancellationRequested(),則會拋出一個 OperationCanceledException 異常。這個異常通常被視為正常的取消流程的一部分,而不是一個需要捕獲和處理的錯誤。

因此,總結(jié)來說,當(dāng) CancellationToken 被取消時,Task.Run 創(chuàng)建的任務(wù)會接收到一個取消請求,但 DoWork 方法本身并不會自動停止執(zhí)行。你需要在 DoWork 方法內(nèi)部編寫邏輯來響應(yīng)這個取消請求并據(jù)此決定是否停止執(zhí)行。同樣,任務(wù)本身也不會立即停止執(zhí)行;它將繼續(xù)執(zhí)行直到遇到檢查取消請求的代碼,并根據(jù)該代碼的邏輯來決定是否停止。

CancellationToken取消了啥

在C#中,當(dāng)DoWork方法通過檢查CancellationToken.IsCancellationRequested屬性并提前返回時,它只是從該方法中退出了。這并不直接結(jié)束或取消底層的Task對象。但是,由于Task.Run創(chuàng)建的Task對象是與DoWork方法的執(zhí)行相關(guān)聯(lián)的,因此當(dāng)DoWork方法返回時,該Task對象會將其狀態(tài)設(shè)置為“已完成”(RanToCompletion),而不是“已取消”(Canceled)。

然而,如果你想要在檢測到取消請求時使Task對象的狀態(tài)變?yōu)?ldquo;已取消”,你需要拋出一個OperationCanceledException。這通常通過調(diào)用CancellationToken.ThrowIfCancellationRequested()方法來實現(xiàn),該方法在取消請求已發(fā)送時會拋出異常。

以下是修改后的DoWork方法示例,它在檢測到取消請求時拋出OperationCanceledException:

static void DoWork(CancellationToken token)
{
    for (int i = 0; i &lt; 10; i++)
    {
        token.ThrowIfCancellationRequested(); // 如果取消請求已發(fā)送,則拋出異常
        
        Console.WriteLine($"DoWork: Working {i + 1}...");
        Thread.Sleep(500); // 模擬耗時操作
    }

    Console.WriteLine("DoWork: Work completed."); // 這行代碼實際上不會被執(zhí)行,因為循環(huán)會在某個點拋出異常
}

在這個例子中,如果CancellationToken的取消請求被發(fā)送(即調(diào)用了CancellationTokenSource.Cancel()方法),ThrowIfCancellationRequested()方法將拋出一個OperationCanceledException異常。這個異常會冒泡到調(diào)用Task.Run的代碼,并最終導(dǎo)致Task對象的狀態(tài)變?yōu)?ldquo;已取消”。

但是,請注意,即使你拋出了OperationCanceledException,Task對象中的任何本地資源(如文件句柄、數(shù)據(jù)庫連接等)仍然需要由你的代碼顯式釋放。異常只是改變了Task的狀態(tài)并通知調(diào)用者任務(wù)已取消,但它不會自動執(zhí)行任何清理工作。

ManualResetEvent

ManualResetEvent是一個同步基元,它允許線程通過信號進行通信。當(dāng)事件處于未發(fā)出狀態(tài)時,線程調(diào)用WaitOne、WaitAny或WaitAll等方法時會阻塞,直到其他線程通過調(diào)用Set方法將事件標(biāo)記為已發(fā)出狀態(tài)。事件保持已發(fā)出狀態(tài),直到調(diào)用Reset方法將其重置為未發(fā)出狀態(tài)。

主要方法

  • Set(): 將ManualResetEvent設(shè)置為已發(fā)出狀態(tài),允許一個或多個等待的線程繼續(xù)執(zhí)行。
  • Reset(): 將ManualResetEvent重置為未發(fā)出狀態(tài),阻塞等待的線程。
  • WaitOne(): 阻塞當(dāng)前線程,直到ManualResetEvent被設(shè)置為已發(fā)出狀態(tài)。

使用示例

創(chuàng)建了幾個Task,它們都等待同一個ManualResetEvent被設(shè)置。一旦事件被設(shè)置,所有等待的Task都會繼續(xù)執(zhí)行。

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static ManualResetEvent resetEvent = new ManualResetEvent(false);

    static async Task Main(string[] args)
    {
        // 創(chuàng)建并啟動多個Task
        Task[] tasks = new Task[3];
        for (int i = 0; i < tasks.Length; i++)
        {
            int taskId = i; // 捕獲循環(huán)變量
            tasks[i] = Task.Run(() => Worker(taskId));
        }

        // 模擬一些工作...
        Console.WriteLine("Main thread is doing some work...");
        await Task.Delay(2000); // 異步等待

        // 設(shè)置事件,允許所有等待的Task繼續(xù)執(zhí)行
        Console.WriteLine("Setting the event to allow all tasks to continue...");
        resetEvent.Set();

        // 等待所有Task完成
        await Task.WhenAll(tasks);

        Console.WriteLine("All tasks have completed.");
    }

    static void Worker(int taskId)
    {
        Console.WriteLine($"Task {taskId} is waiting...");
        resetEvent.WaitOne(); // 等待事件被設(shè)置
        Console.WriteLine($"Task {taskId} continues...");

        // 模擬一些工作...
        Thread.Sleep(1000); // 注意:在async方法中通常使用await Task.Delay()
    }
}

上面的Worker方法實際上是同步的,并且它使用了Thread.Sleep來模擬工作,這通常不是async/await模式中的最佳做法。在async方法中,你應(yīng)該使用await Task.Delay()來異步等待。但是,由于Worker方法被設(shè)計為與ManualResetEvent一起工作,并且是在Task.Run中調(diào)用的,所以這里使用Thread.Sleep是可以接受的。

如果你想要一個完全基于async/await的示例,并且不使用ManualResetEvent(因為async/await提供了更自然的異步等待模式),你可以這樣做:

using System;
using System.Threading.Tasks;

class Program
{
    static Task completionSignal = new TaskCompletionSource<bool>().Task;

    static async Task Main(string[] args)
    {
        // 創(chuàng)建并啟動多個Task
        Task[] tasks = new Task[3];
        for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = Task.Run(async () => await Worker(i));
        }

        // 模擬一些工作...
        Console.WriteLine("Main thread is doing some work...");
        await Task.Delay(2000);

        // 設(shè)置事件,允許所有等待的Task繼續(xù)執(zhí)行
        ((TaskCompletionSource<bool>)completionSignal.Source).SetResult(true);

        // 等待所有Task完成
        await Task.WhenAll(tasks);

        Console.WriteLine("All tasks have completed.");
    }

    static async Task Worker(int taskId)
    {
        Console.WriteLine($"Task {taskId} is waiting...");
        await completionSignal; // 等待事件被設(shè)置
        Console.WriteLine($"Task {taskId} continues...");

        // 模擬一些異步工作...
        await Task.Delay(1000);
    }
}

在這個async/await示例中,我們使用TaskCompletionSource<T>來創(chuàng)建一個可以等待的任務(wù),并在適當(dāng)?shù)臅r候通過調(diào)用SetResult來標(biāo)記它已完成。這是async/await世界中同步多個異步操作的一種更自然的方式。

對于無限循環(huán)的線程,并且需要外部控制暫停/恢復(fù)的場景,使用ManualResetEvent 你可以根據(jù)需要多次設(shè)置和重置它。

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static ManualResetEvent pauseEvent = new ManualResetEvent(true); // 初始化為已設(shè)置狀態(tài),即線程不暫停

    static void Main(string[] args)
    {
        // 啟動工作線程
        Task.Run(WorkerThread);

        // 控制臺輸入來控制暫停和恢復(fù)
        Console.WriteLine("Press 'p' to pause, 'r' to resume, or 'q' to quit.");
        while (true)
        {
            var key = Console.ReadKey(true).KeyChar;
            switch (key)
            {
                case 'p':
                    pauseEvent.Reset(); // 暫停線程
                    Console.WriteLine("Worker thread paused.");
                    break;
                case 'r':
                    pauseEvent.Set(); // 恢復(fù)線程
                    Console.WriteLine("Worker thread resumed.");
                    break;
                case 'q':
                    // 這里需要一種方式來通知工作線程優(yōu)雅地退出,但在這個簡單示例中我們直接退出程序
                    Environment.Exit(0);
                    break;
            }
        }
    }

    static void WorkerThread()
    {
        while (true)
        {
            // 等待暫停事件
            pauseEvent.WaitOne();

            // 執(zhí)行工作...
            Console.WriteLine("Worker thread is working...");

            // 模擬工作耗時
            Thread.Sleep(500);

            // 注意:在真實場景中,你可能不需要在每次循環(huán)迭代中都調(diào)用 WaitOne,
            // 除非你真的希望每次迭代都檢查暫停狀態(tài)。
            // 在這個示例中,我們只是為了演示而這樣做。
        }
    }
}

上面的代碼示例有一個問題:它會在每次循環(huán)迭代中都檢查暫停狀態(tài),這可能會導(dǎo)致不必要的性能開銷。在實際應(yīng)用中,你可能希望只在需要時才檢查暫停狀態(tài),或者將工作分解為更大的塊,并在每個塊之后檢查暫停狀態(tài)。

AutoResetEvent

AutoResetEvent和ManualResetEvent都用于線程間的同步和通信,但它們之間存在一些關(guān)鍵區(qū)別:

  • 重置行為:AutoResetEvent在釋放一個等待線程后會自動重置為未設(shè)定狀態(tài),而ManualResetEvent需要顯式調(diào)用Reset()方法才能重置為未設(shè)定狀態(tài)。
  • 信號通知:AutoResetEvent每次調(diào)用Set()方法時,只允許一個等待線程被喚醒;而ManualResetEvent在調(diào)用Set()方法后,會喚醒所有等待的線程。

AutoResetEvent和ManualResetEvent(實際上是同一事物)的主要特點是其自動重置的行為,這使得它在控制線程執(zhí)行順序和同步線程操作方面非常有用,其他方法調(diào)用都和ManualResetEvent一致。

到此這篇關(guān)于C# Task取消暫停的實現(xiàn)的文章就介紹到這了,更多相關(guān)C# Task取消暫停內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#實現(xiàn)listview Group收縮擴展的方法

    C#實現(xiàn)listview Group收縮擴展的方法

    這篇文章主要介紹了C#實現(xiàn)listview Group收縮擴展的方法,結(jié)合實例形式分析了listview控件的相關(guān)使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-03-03
  • C#中this的用法集錦

    C#中this的用法集錦

    本文給大家匯總介紹了C#中的幾種this用法,相信大家應(yīng)該有用過,但你用過幾種?以下是個人總結(jié)的this幾種用法,歡迎大家拍磚,廢話少說,直接列出用法及相關(guān)代碼。
    2015-06-06
  • C#中的預(yù)定義類型與引用類型

    C#中的預(yù)定義類型與引用類型

    這篇文章介紹了C#中的預(yù)定義類型與引用類型,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • C#使用HtmlAgilityPack實現(xiàn)解析提取HTML內(nèi)容

    C#使用HtmlAgilityPack實現(xiàn)解析提取HTML內(nèi)容

    HtmlAgilityPack是一個HTML解析類庫,這篇文章主要為大家詳細(xì)介紹了C#如何使用HtmlAgilityPack實現(xiàn)解析提取HTML內(nèi)容,感興趣的小伙伴可以參考一下
    2023-12-12
  • C#利用后綴表達式解析計算字符串公式

    C#利用后綴表達式解析計算字符串公式

    當(dāng)我們拿到一個字符串比如:20+31*(100+1)的時候用口算就能算出結(jié)果為3151,因為這是中綴表達式對于人類的思維很簡單,但是對于計算機就比較復(fù)雜了。相對的后綴表達式適合計算機進行計算。本文就來用后綴表達式實現(xiàn)解析計算字符串公式,需要的可以參考一下
    2023-02-02
  • C#裝箱和拆箱原理詳解

    C#裝箱和拆箱原理詳解

    這篇文章通過圖例主要介紹了C#裝箱和拆箱原理,內(nèi)容很簡單,感興趣的小伙伴們可以參考一下
    2015-10-10
  • C#把文件上傳到服務(wù)器中的指定地址

    C#把文件上傳到服務(wù)器中的指定地址

    這篇文章介紹了C#實現(xiàn)文件上傳到服務(wù)器指定地址的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • C#加密知識整合 (AES,MD5,RSA,SHA256)

    C#加密知識整合 (AES,MD5,RSA,SHA256)

    這篇文章主要介紹了c#對于加密的一點整合 (AES,MD5,RSA,SHA256),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • C# Dynamic關(guān)鍵字之:dynamic為什么比反射快的詳解

    C# Dynamic關(guān)鍵字之:dynamic為什么比反射快的詳解

    本篇文章是對C#中dynamic為什么比反射快進行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C#編寫DES加密、解密類

    C#編寫DES加密、解密類

    本文給大家匯總了一下使用C#實現(xiàn)的DES加密、解密類的代碼,十分的簡單實用,有需要的小伙伴可以參考下
    2015-05-05

最新評論