CancellationTokenSourceの誤動作
-
27-10-2019 - |
質問
CancellationTokenSourceでタスクをキャンセルした後、タスクを待つときに問題が発生します。キャンセル呼び出しはタスクを中断しません。待つとき タスクの場合、タスクが中断されることはないため、メインスレッドはブロックします。
これが私のプログラムの簡単な説明です: タスクはchar変数を(「A」から「Z」に)インクリメントし、GUIスレッドに表示します。これを行うために、タスクは、コントロールが作成されたスレッドでデリゲート(this.invoke())を実行します。
RefreshTextBox()-関数をコメントアウトするとすぐにキャンセル呼び出しが機能し、タスクが中断されます。this.invoke()コマンドがタスクの中断を防ぐようです。
以下のコードでも、通常のスレッドで同じ機能を実装しています。そして、私は働きます。タスクの実装とスレッドの実装の違いはどこにありますか? ジェネラコディセタグプレ
解決
これら2つのコードが一緒になってデッドロックを形成します: ジェネラコディセタグプレ
および ジェネラコディセタグプレ
メインスレッドでWait()
を呼び出しており、Invoke()はメインスレッドで処理する必要があります。
代わりにthis.BeginInvoke(...)
を使用することで、デッドロックを解消できます。
スレッドバージョンは、スレッジハンマーである割り込みを使用します。したがって、スレッドは停止信号の後にRefreshTextBox()
を呼び出そうとしません。
他のヒント
これが適合コードです。Henk Holtermanが提案したように、Invoke()ではなくBeginInvoke()を呼び出すようになりました。これは非常にうまく機能し、デッドロックを防ぐ唯一の正しい方法です。考慮しなければならない別のケースもあります。また、BeginInvoke()呼び出しによって与えられるIAsyncResultオブジェクトもあります。このオブジェクトは、非同期呼び出しがすでに完了しているかどうかを確認するために使用します。チェックしない場合は、GUIスレッドがデリゲートを実行するのに十分な速度ではない可能性があり(たとえば、GUIスレッドのどこかにあるsleepステートメント)、この原因として、TestTask()メソッドは常にBeginInvoke()を呼び出しますがGUIスレッドはまだ最後のデリゲートを完了していません。その結果、GUIスレッドがアプリケーションをブロックすることになります。 ジェネラコディセタグプレ