前のコード RulyCancelerクラスの場合 と比較して、CancellationTokenSource
を使用してコードを実行したかったのです。
キャンセルトークン で説明したように、つまり例外をスロー/キャッチせずに使用するにはどうすればよいですか? IsCancellationRequested
プロパティを使用できますか?
私はこれを次のように使用しようとしました:
cancelToken.ThrowIfCancellationRequested();
そして
try
{
new Thread(() => Work(cancelSource.Token)).Start();
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled!");
}
しかし、これにより、メソッドcancelToken.ThrowIfCancellationRequested();
のWork(CancellationToken cancelToken)
で実行時エラーが発生しました。
System.OperationCanceledException was unhandled
Message=The operation was canceled.
Source=mscorlib
StackTrace:
at System.Threading.CancellationToken.ThrowIfCancellationRequested()
at _7CancellationTokens.Token.Work(CancellationToken cancelToken) in C:\xxx\Token.cs:line 33
at _7CancellationTokens.Token.<>c__DisplayClass1.<Main>b__0() in C:\xxx\Token.cs:line 22
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
私が正常に実行したコードは、新しいスレッドでOperationCanceledExceptionをキャッチしました。
using System;
using System.Threading;
namespace _7CancellationTokens
{
internal class Token
{
private static void Main()
{
var cancelSource = new CancellationTokenSource();
new Thread(() =>
{
try
{
Work(cancelSource.Token); //).Start();
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled!");
}
}).Start();
Thread.Sleep(1000);
cancelSource.Cancel(); // Safely cancel worker.
Console.ReadLine();
}
private static void Work(CancellationToken cancelToken)
{
while (true)
{
Console.Write("345");
cancelToken.ThrowIfCancellationRequested();
}
}
}
}
次のように作業メソッドを実装できます。
private static void Work(CancellationToken cancelToken)
{
while (true)
{
if(cancelToken.IsCancellationRequested)
{
return;
}
Console.Write("345");
}
}
それでおしまい。常に自分でキャンセルを処理する必要があります-終了する適切な時間になったらメソッドを終了します(作業とデータが一貫した状態になるように)
PDATE:ループボディ全体で安全に実行を停止できる終了ポイントが少ないことが多いため、while (!cancelToken.IsCancellationRequested)
を記述しないことをお勧めします。 。ですから、意図が異なるため、その条件を混ぜない方が良いと思います。
しゅう
Stackoverflowに投稿されたすべてを盲目的に信頼するべきではありません。 Jensコードのコメントは正しくありません。パラメーターは、例外がスローされるかどうかを制御しません。
MSDNはそのパラメーターが何を制御するかを非常に明確にしています。読んでいますか? http://msdn.Microsoft.com/en-us/library/dd321703(v = vs.110).aspx
ThrowOnFirstExceptionがtrueの場合、例外はすぐにCancelの呼び出しから伝達され、残りのコールバックとキャンセル可能な操作が処理されないようにします。 throwOnFirstExceptionがfalseの場合、このオーバーロードはAggregateExceptionにスローされたすべての例外を集約し、例外をスローする1つのコールバックが他の登録済みコールバックの実行を妨げないようにします。
トークン自体ではなくCancellationTokenSourceでCancelが呼び出され、ソースが管理する各トークンの状態を変更するため、変数名も間違っています。
can例外を処理せずにThrowIfCancellationRequestedを使用します!
ThrowIfCancellationRequestedの使用は、タスク(スレッドではない)内から使用することを意図しています。タスク内で使用する場合、例外を自分で処理する必要はありません(未処理の例外エラーが発生します)。タスクが終了し、Task.IsCancelledプロパティがTrueになります。例外処理は必要ありません。
特定のケースでは、スレッドをタスクに変更します。
try
{
Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}
if (t.IsCancelled)
Console.WriteLine("Canceled!");
}
キャンセルトークンを使用してタスクを作成できます。バックグラウンドでアプリを実行すると、このトークンをキャンセルできます。
これはPCLで行うことができます https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle
var cancelToken = new CancellationTokenSource();
Task.Factory.StartNew(async () => {
await Task.Delay(10000);
// call web API
}, cancelToken.Token);
//this stops the Task:
cancelToken.Cancel(false);
別のソリューションは、Xamarin.Formsのユーザータイマーです。アプリがバックグラウンドに移動したらタイマーを停止します https://xamarinhelp.com/xamarin-forms-timer/
CancellationToken
をタスクに渡す必要があります。タスクは定期的にトークンを監視して、キャンセルが要求されているかどうかを確認します。
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
Task task = Task.Run(() => {
while(!token.IsCancellationRequested) {
Console.Write("*");
Thread.Sleep(1000);
}
}, token);
Console.WriteLine("Press enter to stop the task");
Console.ReadLine();
cancellationTokenSource.Cancel();
この場合、キャンセルが要求されると操作が終了し、Task
の状態はRanToCompletion
になります。 タスクがキャンセルされたであることを確認したい場合は、ThrowIfCancellationRequested
を使用してOperationCanceledException
例外をスローする必要があります。
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested) {
Console.Write("*");
Thread.Sleep(1000);
}
token.ThrowIfCancellationRequested();
}, token)
.ContinueWith(t =>
{
t.Exception?.Handle(e => true);
Console.WriteLine("You have canceled the task");
},TaskContinuationOptions.OnlyOnCanceled);
Console.WriteLine("Press enter to stop the task");
Console.ReadLine();
cancellationTokenSource.Cancel();
task.Wait();
これが理解を深めるのに役立つことを願っています。