keijikk
1/14/2016 - 8:36 AM

タスクのキャンセル法 http://outofmem.tumblr.com/post/81461413951/c%E3%82%BF%E3%82%B9%E3%82%AF%E3%81%AE%E3%82%AD%E3%83%A3%E3%83%B3%E3%82%BB%E3%83%AB%E

// TaskCreationOptionsと併用するときの注意

// タスクにCancellationTokenだけでなく、TaskCreationOptionsも設定したい場合は
// ちょっとした注意が必要です。
// と言っても、大したことではないです。TaskFactoryのStartNewメソッドに
// CancellationTokenとTaskCreationOptionsを同時に受け付けるオーバーロードがないだけです。
// Taskのコンストラクタにはあるのに何でないんだ、って感じですが、もしStartNewを
// 使いたい場合はこのオーバーロードを使いましょう。

// StartNewメソッドはやたらとオーバーロードが多い上に第二引数にobjectを
// 受け取っちゃうオーバーロードが多数存在するので、引数の順番を間違えてハマらないようにしましょう。


Task.Factory.StartNew(() =>
{
    // TODO:非同期処理
     
     
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
// それすら面倒だと思ったらCancellationTokenSource.Cancel(Boolean)の方を使いましょう。
// タスクを即時終了する

private CancellationTokenSource _tokenSource = null;
 
private void btnStart_Click(object sender, EventArgs e)
{
    if(_tokenSource == null) _tokenSource = new CancellationTokenSource();
    var token = _tokenSource.Token;
     
    Task.Factory.StartNew(() =>
    {
        // TODO:非同期処理
         
         
    }, token).ContinueWith(t =>
    {
        // TODO:あとしまつ
        _tokenSource.Dispose();
        _tokenSource = null;
         
        if (t.IsCanceled)
        {
            // TODO:キャンセルされたときの処理
        }
    });
}
 
private void btnStop_Click(object sender, EventArgs e)
{
    // 即例外を投げてキャンセルさせる
    if(_tokenSource != null) _tokenSource.Cancel(true);
}
// これだと面倒なので、
// キャンセル処理をContinueWithでまとめてやりたい場合は、
// CancellationToken.ThrowIfCancellationRequestedメソッドを使うと楽です。

Task.Factory.StartNew(() =>
{
    // TODO:非同期処理
     
    // キャンセル通知が来てたら例外を投げてタスクを終了させる
    token.ThrowIfCancellationRequested();
     
    // TODO:続きの処理
     
    token.ThrowIfCancellationRequested();
     
}, token).ContinueWith(t =>
{
    // TODO:あとしまつ
    _tokenSource.Dispose();
    _tokenSource = null;
     
    if (t.IsCanceled)
    {
        // TODO:キャンセルされたときの処理
    }
});
// CancellationTokenSource.Cancelメソッドを使うとCancellationTokenに通知が飛びます。
// 飛んでいったからといって、何がどうなるわけでもないです。非同期処理中に何度か
// IsCancellationRequestedプロパティを見てやる必要があります。

Task.Factory.StartNew(() =>
{
    // TODO:非同期処理
     
    if (token.IsCancellationRequested)
    {
        // TODO:キャンセル処理
        return;
    }
     
    // TODO:続きの処理
     
    if (token.IsCancellationRequested)
    {
        // TODO:キャンセル処理
        return;
    }
     
}, token).ContinueWith(t =>
{
    // TODO:あとしまつ
    _tokenSource.Dispose();
    _tokenSource = null;
     
     
});
private CancellationTokenSource _tokenSource = null;
 
private void btnStart_Click(object sender, EventArgs e)
{
    if(_tokenSource == null) _tokenSource = new CancellationTokenSource();
    var token = _tokenSource.Token;
     
    Task.Factory.StartNew(() =>
    {
        // TODO:非同期処理
         
         
    }, token).ContinueWith(t =>
    {
        // TODO:あとしまつ
        _tokenSource.Dispose();
        _tokenSource = null;
         
         
    });
}
 
private void btnStop_Click(object sender, EventArgs e)
{
    if(_tokenSource != null) _tokenSource.Cancel();
}