當任務被 Cancel 後,我們需要一些進行一些處理,例如 UI 的顯示,使用者事件的記錄等。以下程式由上一次的範例繼續演變下去。
要監看任務是否被取消,有下列的方法。
方法1:使用Polling (輪詢)
這個方法即上次的演示,是在 Task body 內的迴圈中使用 tokenSource.IsCancellationRequested 來得到是否任務被取消。
方法2:使用Delegate
將程式重構,在建構子時建立 task,並在使用者按「start」鍵時啟始這個任務。
using System; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; namespace TPL_CancelAnApp { public partial class MainWindow : Window { //建立 CancellationTokenSource CancellationTokenSource tokenSource = new CancellationTokenSource(); Task task; public MainWindow() { InitializeComponent(); InitialTask(); } private void InitialTask() { task = new Task(() => { long total = 0; while (total < 1000) { total++; Thread.Sleep(2); Action<string> action = new Action<string>(s => txtTotal.Text = s); txtTotal.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString()); //當收到要求取消任務時,我就終止任務 tokenSource.Token.ThrowIfCancellationRequested(); }; }, tokenSource.Token); //具有這個 Token 的來源可以取消這個任務 tokenSource.Token.Register(() => txtStatus.Text = "使用者要求停止。"); } private void btnStart_Click(object sender, RoutedEventArgs e) { txtStatus.Text = "進行中"; task.Start(); } private void btnStop_Click(object sender, RoutedEventArgs e) { btnStart.IsEnabled = false; tokenSource.Cancel(); } } }注意到在 InitialTask() 中,我增加了一行 tokenSource.Token.Register(…,這一行註冊了一個 delegate,當任務被取消時,會回過頭來呼叫該 delegate。
範例下載
方法3:使用Wait Handle
WaitHandle 是多執行緒程式中常用的物件,在TPL 中也不例外。在下例中,我建立了一個 task2,並且等到 task的Cancel呼叫後才會執行。
private void InitialTask() { CancellationToken token = tokenSource.Token; task = new Task(() => { long total = 0; … }, token); //具有這個 Token 的來源可以取消這個任務 Task task2 = new Task(() => { token.WaitHandle.WaitOne(); //直到 tokenSource.Cancel() 被呼叫後才會往下執行 txtStatus.Dispatcher.BeginInvoke(new Action(() => txtStatus.Text = "使用者要求停止。")); }); task2.Start(); }範例下載
沒有留言:
張貼留言