x_xさんの回答を補足します(コードができたので)。
私もCancellationTokenについて悩んだくちです。わかる範囲で説明をば。。。
まず、登場人物が二人います。CancellationTokenSourceと、それから取得できるCancellationTokenです。このソースを使うことで、トークンにキャンセル指示を出すことができます。ただし、実際になにかしらキャンセルが行われるわけではありません。キャンセル指示が出されたことをトークンを使って確認することができるだけです。"トークンにキャンセル指示が出されたかどうか確認し、指示が出されていればキャンセル処理を行う" という処理を自分で実装する必要がある点に気を付けてください(キャンセルさせたい処理がループであれば、ループの中でトークンを確認し、必要に応じてブレークする)。そうすると、参考のリンクが理解しやすいと思います。
また、キャンセル指示はリセットできません。もう一度処理を実行し、キャンセルしたい場合、ソースを再作成しなければならないことに留意してください。
実際に書いてみると次のようになります。
button1を何度も押せるのはまずいので、状況に応じて有効化無効化します。
c#
1using System;
2using System.Diagnostics;
3using System.Threading;
4using System.Threading.Tasks;
5using System.Windows.Forms;
6
7namespace WindowsFormsApp1
8{
9 public partial class Form1 : Form
10 {
11 // キャンセレーショントークンソース(Button2で参照します)
12 private CancellationTokenSource CancellationTokenSource;
13
14 public Form1()
15 {
16 InitializeComponent();
17
18 button1.Enabled = true;
19 button2.Enabled = false;
20 }
21
22 // 開始ボタン
23 public void button1_Click(object sender, EventArgs e)
24 {
25 button1.Enabled = false;
26 button2.Enabled = true;
27
28 // ソースを作成します
29 this.CancellationTokenSource = new CancellationTokenSource();
30
31 // 処理を開始します(キャンセルトークンを渡す必要があります)
32 First_run(CancellationTokenSource.Token);
33 }
34 // キャンセルボタン
35 public void button2_Click(object sender, EventArgs e)
36 {
37 // キャンセル指示を出します
38 CancellationTokenSource.Cancel();
39
40 // ソースを破棄します(使い切りのものなので)
41 CancellationTokenSource = null;
42
43 button1.Enabled = true;
44 button2.Enabled = false;
45 }
46
47 public async Task First_run(CancellationToken token)
48 {
49 await com(token);
50 com2();
51
52 }
53 private async Task com(CancellationToken token)
54 {
55 var count = 0;
56 var loopNum = 300;
57
58 //ループ処理(trueになればループ終了)
59 while (count < loopNum)
60 {
61 // 少し重い処理(0.01sec)
62 await Task.Delay(TimeSpan.FromSeconds(0.01));
63 Debug.WriteLine("com実行中...");
64
65 // キャンセル指示が出ているか確認します
66 if (token.IsCancellationRequested)
67 {
68 // キャンセル処理
69 Debug.WriteLine("comをキャンセルします...");
70
71 // ループ終了
72 break;
73 }
74
75 loopNum++;
76 }
77
78 // キャンセルしてもここは実行されるので注意してください
79 }
80 public void com2()
81 {
82 Debug.WriteLine("com2実行中...");
83 }
84 }
85}
少し気になったのですが、ループ処理内で行っている処理は非同期処理でしょうか。
そうでなければUIが固まり、ボタンを押すに押せなくなるかもしれません。。
同期処理になっているのであれば、ループ全体を Task.Run(() => { .... }) の中に入れてしまいましょう。
c#
1 await Task.Run(() =>
2 {
3 //ループ処理(trueになればループ終了)
4 while (count < loopNum)
5 {
6 // 少し重い処理(0.01sec)
7 //await Task.Delay(TimeSpan.FromSeconds(0.01));
8 Debug.WriteLine("com実行中...");
9
10 // キャンセル指示が出ているか確認します
11 if (token.IsCancellationRequested)
12 {
13 // キャンセル処理
14 Debug.WriteLine("comをキャンセルします...");
15
16 // ループ終了
17 break;
18 }
19
20 //loopNum++;
21 }
22 }, token);
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2018/10/04 04:25 編集
2018/09/19 08:09
退会済みユーザー
2018/09/26 14:37 編集