[C#.NET][TPL] Task 生命週期狀態
不論玩什麼技術,瞭解生命週期是很重要的一件事,TaskStatus 列舉 是平行運算函式庫的生命週期狀態,TaskStatus 列舉 的成員如下
初始化狀態:
- Created
- WaitingForActivation
- WaitingToRun
最終狀態:
- RanToCompletion
- Canceled
- Faulted
由下圖所示:
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); }
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); }
執行結果如下:
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); }
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); }
執行結果如下:
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); }); }
執行結果如下:
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); }
執行結果如下:
以上簡單的程式碼就能測出任務狀態,但是,我試了好久無法測出 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)); }
執行結果如下:
主任務完成後跳出下圖:
下圖是調用方法狀態改變的順序:
還缺一個 WaitingForChildrenToComplete 狀態不知如何觀察,知道的人可以跟我講一下喔。
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET