當任務被 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();
}
範例下載
沒有留言:
張貼留言