[C#.NET][TPL] Task 生命週期狀態

[C#.NET][TPL] Task 生命週期狀態

不論玩什麼技術,瞭解生命週期是很重要的一件事,TaskStatus 列舉 是平行運算函式庫的生命週期狀態,TaskStatus 列舉 的成員如下

image

 

初始化狀態:

  1. Created
  2. WaitingForActivation
  3. WaitingToRun

 

最終狀態:

  1. RanToCompletion
  2. Canceled
  3. Faulted

由下圖所示:

image

 

Created:

這很容易理解,建立任務但未開始執行(未調用Start)

private void DoWork1()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task t = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            return false;
        }, 10000);
    }, cts.Token);
    var status = t.Status.ToString();
    MessageBox.Show(status);
}


 

執行結果如下:
SNAGHTML11218f3f

 

 

WaitingToRun:

已經排定任務,正要啟動,就算立即調用 Start 方法也不見得會立馬啟動,千萬要記住不管是平行運算還是傳統的執行緒,都不會立馬啟動。

private void DoWork2()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task t = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            return false;
        }, 10000);
    }, cts.Token);
    t.Start();
    var status = t.Status.ToString();
    MessageBox.Show(status);
}


執行結果如下:

SNAGHTML11226888

 

Running:

調用 Start 後,動點手腳才能看觀察任務已經在執行。

private void DoWork3()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task t = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            return false;
        }, 10000);
    }, cts.Token);
    t.Start();
    SpinWait.SpinUntil(() => false, 100);
    var status = t.Status.ToString();
    MessageBox.Show(status);
}

 

執行結果如下:
SNAGHTML112061ea

 

 

Canceled:

調用CancellationTokenSource.Cancel,在方法體內要調用ThrowIfCancellationRequested方法,這時就能看到狀態是Cancel

private void DoWork4()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task t = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            cts.Token.ThrowIfCancellationRequested();
            return false;
        }, 10000);
    }, cts.Token);
    t.Start();
    SpinWait.SpinUntil(() => false, 100);
    cts.Cancel();
    SpinWait.SpinUntil(() => false, 100);
    var status = t.Status.ToString();
    MessageBox.Show(status);
}

 

執行結果如下:

SNAGHTML111f8834

 

RanToCompletion:

任務完成,在這裡我利用Task.ContinueWith方法來叫起另外一個任務,用來觀察任務完成。

private void DoWork5()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task t = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            cts.Token.ThrowIfCancellationRequested();
            return false;
        }, 10000);
    }, cts.Token);
    t.Start();
    t.ContinueWith((t1) =>
    {
        var status = t.Status.ToString();
        MessageBox.Show(status);
    });
}

 

執行結果如下:

 

SNAGHTML111cc7ac

 

Faulted:

在這裡我仍是接續另一個子任務,用來觀察父任務的狀態,故意拋出一個例外,讓子任務接收。

private void DoWork6()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task t = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            cts.Token.ThrowIfCancellationRequested();
            return false;
        }, 1000);
        throw new Exception("Demo");
    }, cts.Token);
    t.Start();
    t.ContinueWith((t1) =>
    {
        try
        {
            t.Wait();
        }
        catch (AggregateException ex)
        {
            //TODO:補捉例外
            foreach (var innerException in ex.InnerExceptions)
            {
                Console.WriteLine(innerException.ToString());
            }
        }
        finally
        {
            var status = t.Status.ToString();
            MessageBox.Show(status);
        }
    }, TaskContinuationOptions.OnlyOnFaulted);
}

 

執行結果如下:

 

SNAGHTML1128b591

 

以上簡單的程式碼就能測出任務狀態,但是,我試了好久無法測出 WaitingForActivation 狀態在什麼情況下會出現,若知道的人可以告訴我一下。

更多資料可參考

http://msdn.microsoft.com/en-us/library/ff963549.aspx


補充:

WaitingForActivation:
用Task.ContinueXXX 關鍵字的 Task,就能觀察到這個狀況。

我返回 t1 便能觀察到它的 TaskStatus

private void DoWork7()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    var mainTask = new Task(() =>
    {
        SpinWait.SpinUntil(() =>
        {
            cts.Token.ThrowIfCancellationRequested();
            return false;
        }, 10000);
    }, cts.Token);

    var subTask = mainTask.ContinueWith((t1) =>
    {
        var status = mainTask.Status.ToString();
        MessageBox.Show(status);
        return t1;
    });

    mainTask.Start();
    Thread.Sleep(100);

    MessageBox.Show(string.Format("main task status:{0}\r\nsub task status:{1}", mainTask.Status, subTask.Status));
}

 

執行結果如下:

 

SNAGHTML1f5a2423

 

主任務完成後跳出下圖:

SNAGHTML1f5ac9d9


下圖是調用方法狀態改變的順序:

image

還缺一個 WaitingForChildrenToComplete 狀態不知如何觀察,知道的人可以跟我講一下喔。

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo