2010年6月15日 星期二

TPL 學習日記(4): 取消多個任務

接下來看比較複雜的範例。

取消多個任務

多個任務在不同時間開始執行,但需要在同一個時間結束。以下是畫面。

image

需求

當我們按上面的 Start 鍵,就開始第一個計數器。當按下面的 Start 鍵,就開始第二個計數器。而按 Stop All 鍵時,兩個計數器同時停止。

在 Task 的初始時,指定同一個 CancelTokenSource 的 CancelToken,就可以使用同一個CancelTokenSource 來 Cancel 多個 Task

CancelMutilpleTasks.xaml
<Window x:Class="TPL_CancelAnApp.CancelMutilpleTasks"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <Grid>
    <StackPanel >
      <StackPanel>
        <TextBlock x:Name="txtTotal1" />
        <Button x:Name="btnStart1" Click="btnStart_Click">Start</Button>
      </StackPanel>
      <StackPanel>
        <TextBlock x:Name="txtTotal2" />
        <Button x:Name="btnStart2" Click="btnStart_Click">Start</Button>
      </StackPanel>
      <Button x:Name="btnStop" Click="btnStop_Click">Stop All</Button>
      <TextBlock Name="txtStatus" />
    </StackPanel>
  </Grid>
</Window>
CancelMutilpleTasks.xaml.cs
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Controls;

namespace TPL_CancelAnApp
{
  public partial class CancelMutilpleTasks : Window
  {
    CancellationTokenSource tokenSource = new CancellationTokenSource();
    Task[] tasks = new Task[2];
    public CancelMutilpleTasks()
    {
      InitializeComponent();
      InitialTask();
    }

    private void InitialTask()
    {
      CancellationToken token = tokenSource.Token;
      //建立第一個 task
      tasks[0] = new Task(() =>
      {
        long total = 0;
        while (total < 1000)
        {
          total++;
          Thread.Sleep(2);
          Action<string> action = new Action<string>(s => txtTotal1.Text = s);
          txtTotal1.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString());
          token.ThrowIfCancellationRequested();
        };
      }, token);
      //建立第二個 task
      tasks[1] = new Task(() =>
      {
        long total = 0;
        while (total < 1000)
        {
          total++;
          Thread.Sleep(2);
          Action<string> action = new Action<string>(s => txtTotal2.Text = s);
          txtTotal2.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString());
          token.ThrowIfCancellationRequested();
        };
      }, token);

      Task.Factory.StartNew(() =>
      {
        token.WaitHandle.WaitOne();
        txtStatus.Dispatcher.BeginInvoke(new Action(() => txtStatus.Text = "使用者要求停止。"));
      });
    }

    private void btnStart_Click(object sender, RoutedEventArgs e)
    {
      txtStatus.Text = "進行中";
      Button button = sender as Button;
      int index = int.Parse(button.Name.Substring(button.Name.Length - 1));
      tasks[index-1].Start(); //啟動指定的任務
    }

    private void btnStop_Click(object sender, RoutedEventArgs e)
    {
      btnStart2.IsEnabled = btnStart1.IsEnabled = false;
      tokenSource.Cancel(); //發出 Cencel 的訊號
    }
  }
}

範例下載

沒有留言:

Share with Facebook