回答編集履歴

1

追記

2016/08/05 06:17

投稿

tamoto
tamoto

スコア4110

test CHANGED
@@ -33,3 +33,111 @@
33
33
  ```
34
34
 
35
35
  CancelTaskA()が同期メソッドであるという前提です。App_FormClosingの処理が完了するまではフォームは閉じないので、複雑なことはせず、単純にTaskAのキャンセル処理を完了してください。
36
+
37
+
38
+
39
+ ---
40
+
41
+
42
+
43
+ 追記
44
+
45
+
46
+
47
+ CancellationTokenによるTaskの実行キャンセルは、あくまでC#のコード上でキャンセル処理を記述するものであり、何らかの処理(== OSコマンドによる重い処理)を途中で割り込み停止することはできません。最小単位では、TaskA内のwhile内の1行単位でキャンセルを行えることになります。その場合は記述はあまり難しくはないです。
48
+
49
+
50
+
51
+ というわけで、当初の目的であった「フォームを閉じる際、Taskをキャンセルしてから閉じる」部分のみを実現する場合は、以下のコードになります。
52
+
53
+
54
+
55
+ ```csharp
56
+
57
+ // App_FormClosingは同期メソッドとする
58
+
59
+ void App_FormClosing(object sender, FormClosingEventArgs e) {
60
+
61
+ CancelAllTask(); // フォームを閉じる時は、TaskAのキャンセルをリクエストする以上のことはしない
62
+
63
+ }
64
+
65
+
66
+
67
+ private CancellationTokenSource m_CTS = new CancellationTokenSource();
68
+
69
+
70
+
71
+ private Task TaskA()
72
+
73
+ {
74
+
75
+ return Task.Factory.StartNew(async () =>
76
+
77
+ {
78
+
79
+ while (true)
80
+
81
+ {
82
+
83
+ await Task.Delay(2000, m_CTS.Token); // Task.DelayにCancellationTokenを渡すことで、待ち時間中にキャンセルされた場合、続きの実行は行われない
84
+
85
+
86
+
87
+ // 以下何らかの処理;
88
+
89
+ {
90
+
91
+ //もし、「何らかの処理」のコードの途中でキャンセル可能な部分がある場合はそこに以下の一行を挟む
92
+
93
+ m_CTS.Token.ThrowIfCancellationRequested();
94
+
95
+ }
96
+
97
+ }
98
+
99
+ }, m_CTS.Token);
100
+
101
+ }
102
+
103
+
104
+
105
+ private void CancelAllTask()
106
+
107
+ {
108
+
109
+ m_CTS.Cancel();
110
+
111
+
112
+
113
+ // もし、「何らかの処理」を割り込み停止する手段があるならここに記述
114
+
115
+ }
116
+
117
+
118
+
119
+ ```
120
+
121
+
122
+
123
+ 以上のコードについて。
124
+
125
+ まず、「何らかの処理(== C#外の処理)」が既に実行中である場合、Taskのキャンセルでそれを停止することはできないので、1コマンド分の実行は諦めるしかないです。これを停止したいとなると、今度はOSコマンドのほうにキャンセル命令を投げる手段を改めて探さなければなりません。
126
+
127
+ そして、「何らかの処理」を停止できないのであれば、Taskの完全終了を確認する必要もなくなるので、キャンセルをリクエストしてフォームを閉じてしまえば良いです。TaskAはキャンセル可能な部分に入った瞬間にキャンセルされます。
128
+
129
+ ループ内でのキャンセル方法について、break;で抜けるとTaskのStatusがCompletedになりますが、この状況ではCanceledが得られることが望ましいので、ThrowIfCancellationRequestedを使ってキャンセルを行います。
130
+
131
+
132
+
133
+ 本来は「何らかの処理」を含めてキャンセルしたいと思われますが、そちらのほうはTaskでは実現できません。
134
+
135
+ もし、「TaskAの「何らかの処理」が実行中ではなくなり、TaskAのキャンセルが完了するまでフォームを閉じたくない」なら、CancellAllTaskメソッド内に以下の一行を追加して下さい。
136
+
137
+ ```csharp
138
+
139
+ taskA.ContinueWith(_ => { /* キャンセル完了時の処理 */ }).Wait();
140
+
141
+ ```
142
+
143
+