1. 程式人生 > >C# 多執行緒六之Task(任務)二

C# 多執行緒六之Task(任務)二

前面介紹了Task的由來,以及簡單的使用,包括開啟任務,處理任務的超時、異常、取消、以及如果獲取任務的返回值,在回去返回值之後,立即喚起新的執行緒處理返回值、且如果前面的任務發生異常,喚起任務如果有效的處理異常等關於Task的知識。所以本文將介紹Task更多的用法和特性.

 

一、如果通過一個任務建立多個子任務.

1、Task支援一個任務,建立多個子任務,並且保持關聯.

        static void Main(string[] args)
        {
            var parentTask = new Task<int[]>(() =>
            {
                
//開啟多個子任務 var results = new int[2]; //建立子任務,並將子任務的值賦給results變數,並通過TaskCreationOptions.AttachedToParent,將其關聯到父任務,如果不指定,該任務將獨立於父任務單獨執行 //這裡有個奇怪的問題,只能使用new Task的方式去建立關聯到父任務的子任務,因為Task.Run沒有提供這個方法,可以通過擴充套件方法解決這個問題 new Task(() => results[0] = ChildThreadOne(), TaskCreationOptions.AttachedToParent).Start();
new Task(() => results[1] = ChildThreadTwo(), TaskCreationOptions.AttachedToParent).Start(); return results; }); parentTask.Start(); parentTask.ContinueWith(x => { Console.WriteLine("當父任務執行完畢時,CLR會喚起一個新執行緒,將父任務的返回值(子任務的返回值)輸出,所以這裡不會有任何的執行緒發生阻塞
"); foreach (var re in parentTask.Result) { Console.WriteLine("子任務的返回值分別為:{0}", re); } }); Console.WriteLine("主執行緒不會阻塞,它會繼續執行"); Console.ReadKey();//必須加這行程式碼,因為Task時執行緒池執行緒,屬於後臺執行緒 } /// <summary> /// 子任務一 /// </summary> static int ChildThreadOne() { Thread.Sleep(2000);//模擬長時間計算操作 Console.WriteLine("子任務一完成了計算任務,並返回值:{0}", 6); return 6; } /// <summary> /// 子任務一 /// </summary> static int ChildThreadTwo() { Thread.Sleep(2000);//模擬長時間計算操作 Console.WriteLine("子任務二完成了計算任務,並返回值:{0}", 6); return 6; }

 

 

二、關於Task的資源釋放問題.

如果你看過Task的原始碼,你會發現下面這個有趣的問題:

ok,你會想它想釋放什麼呢?

沒錯,當Task任務,指定了TaskContinuationOptions列舉狀態,且指定的值如下:

那麼,直接return,什麼資源釋放操作都不做.

如果任務沒有完成,就呼叫Dispose方法,那麼直接拋異常,如果完成了,它就釋放了ManualResetEventSlim訊號量(後面的文章會介紹).所以如果你在task中使用了其它的一些非託管資源,那麼最好在程式碼裡自己手動釋放,在使用完之後。或者自己實現了Task的派生類,把需要用的非託管資源加進去,然後在使用完派生類之後,呼叫Dispose方法.

 

三、關於Task的幾個常用屬性

1、Id屬性,每個Task物件都有一個Id屬性,全域性唯一,且每次建立新的任務,這個值都會遞增1.

2、TaskStatus狀態

    //
    // 摘要:
    //     表示 System.Threading.Tasks.Task 的生命週期中的當前階段。
    public enum TaskStatus
    {
        //
        // 摘要:
        //     該任務已初始化,但尚未被計劃。
        Created = 0,
        //
        // 摘要:
        //     該任務正在等待 .NET Framework 基礎結構在內部將其啟用並進行計劃。
        WaitingForActivation = 1,
        //
        // 摘要:
        //     該任務已被計劃執行,但尚未開始執行。
        WaitingToRun = 2,
        //
        // 摘要:
        //     該任務正在執行,但尚未完成。
        Running = 3,
        //
        // 摘要:
        //     該任務已完成執行,正在隱式等待附加的子任務完成。
        WaitingForChildrenToComplete = 4,
        //
        // 摘要:
        //     已成功完成執行的任務。
        RanToCompletion = 5,
        //
        // 摘要:
        //     該任務已通過對其自身的 CancellationToken 引發 OperationCanceledException 對取消進行了確認,此時該標記處於已傳送訊號狀態;或者在該任務開始執行之前,已向該任務的
        //     CancellationToken 發出了訊號。 有關詳細資訊,請參閱任務取消。
        Canceled = 6,
        //
        // 摘要:
        //     由於未處理異常的原因而完成的任務。
        Faulted = 7
    }

構造完Task物件是,狀態為Created,當任務啟動時,狀態變為WaitingToRun,當Task實際線上程上執行時,狀態變為Running.如果當前任務為父任務,且它已經執行完畢,等待其它子任務執行完畢的時候,其狀態變為WaitingForChildrenToComplete.如果任務完成可能會出現以下幾種狀態:RanToCompletion(已成功完成執行的任務)、Canceled(取消狀態)、

Faulted(任務出錯).

這裡需要注意一個特殊的狀態WaitingForActivation

當使用Task物件的ContinueWith的Task物件處理改狀態,意味者該Task任務的排程由任務基礎結構控制.也就是該任務的排程只有當前面的任務執行完之後,由CLR發起執行呼叫.