質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

1回答

4021閲覧

(C#)タスクのタイムアウトについて

git

総合スコア8

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

2クリップ

投稿2018/09/18 13:21

Taskを用いてマルチスレッド処理をする場合に、タイムアウトをどう実装すべきか悩んでおります。
どのような実装が考えられるか、アドバイスをお願いします。

処理をタイムアウトする場合にはCancellationTokenSourceのCancelAfterメソッドが推奨されているようですが、
IsCancellationRequestedプロパティをポーリングする必要があるのが少し気になっています。
以下のようなコードを想定すると、プロパティをチェックができないためです。

C#

1var cts = new CancellationTokenSource(); 2cts.CancelAfter(10*1000); 3 4Task.Factory.StartNew( ()=>{ 5 //何かしらの重い処理 6 //外部ライブラリの重い計算ライブラリを想定 7 HeavyMethod(); 8},cts);

await Task.WhenAny(task, Task.Delay(10*1000)) != taskと記述してタイムアウトを実現する方法もあるようですが、
できればasync-await句を使用せずに書きたいです。
またtaskが実行中でDelay処理が先に完了した場合に、taskがどう処理されるかも分かりません。

cts.IsCancelRequestedを外からチェックして、taskを安全に停止する方法も考えましたが、
task.Dispose()をしてもスレッドが処理を停止しなかったため諦めました...。

StackOverflowなども調べてみましたが良い案が見つかりませんでした。

抽象的な質問で申し訳ありませんが、よろしくお願いいたします。

退会済みユーザー👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hihijiji

2018/09/19 04:02

async と await がTask の一番美味しい所だと思うのですが、使いたくない理由は何ですか?
guest

回答1

0

調べた限り、Taskを使用するのはよくないと思われます。

確認した結果、スレッドを使用するのが良いかと存じます。
注意点としては以下の通り。

  • スレッド生成にはコストがかかるので、大量に動かす場合などは、ThreadPoolを使用する
  • スレッド内の例外は自分でハンドリングすること(Abortの際に呼び出し側で例外が発生することがある)

Program.cs

1var sw = Stopwatch.StartNew(); 2Console.WriteLine("[{0}]starting", sw.Elapsed); 3var thread = new Thread(new ThreadStart(() => { 4 for (var i = 0; i < 100; i++) 5 { 6 Thread.Sleep(1000); 7 Console.WriteLine("[{0}]waiting... {1}", sw.Elapsed, i); 8 } 9 Console.WriteLine("[{0}]done", sw.Elapsed); 10})); 11thread.Start(); 12Console.WriteLine("[{0}]started", sw.Elapsed); 13// タスクが完了(キャンセル)するまで待つ 14Thread.Sleep(10 * 1000); 15// スレッドが生きている場合、中断する 16if (thread.IsAlive) 17{ 18 Console.WriteLine("[{0}]fire abort", sw.Elapsed); 19 thread.Abort(); 20} 21Console.WriteLine("[{0}]task finished", sw.Elapsed); 22sw.Stop(); 23Console.ReadKey(); 24

添付資料

失敗例を上げておきます。想定では途中で例外が発生し、タスクが中断のはずが、動き続けます。

Program.cs

1var sw = Stopwatch.StartNew(); 2Console.WriteLine("[{0}]starting", sw.Elapsed); 3using (var cts = new CancellationTokenSource()) 4using (var task = Task.Factory.StartNew(() => 5{ 6 for (var i = 0; i < 100; i++) 7 { 8 Thread.Sleep(1000); 9 Console.WriteLine("[{0}]waiting... {1} {2}", sw.Elapsed, i, cts.Token.IsCancellationRequested); 10 } 11 Console.WriteLine("[{0}]done", sw.Elapsed); 12}, cts.Token) 13) 14{ 15 Console.WriteLine("[{0}]started", sw.Elapsed); 16 if (!task.Wait(10 * 1000)) 17 { 18 Console.WriteLine("[{0}]fire abort", sw.Elapsed); 19 //キャンセルを伝え、直ちに例外を発生させる 20 cts.Cancel(true); 21 } 22 // タスクが完了(キャンセル)するはず 23 Console.WriteLine("[{0}]task finished", sw.Elapsed); 24 Thread.Sleep(1000); 25 //ここを抜けるときに例外発生(InvalidOperation、タスクが止まらない) 26}
[00:00:00.0001531]starting [00:00:00.0358243]started [00:00:01.0408594]waiting... 0 False [00:00:02.0419494]waiting... 1 False [00:00:03.0422047]waiting... 2 False [00:00:04.0425413]waiting... 3 False [00:00:05.0429124]waiting... 4 False [00:00:06.0433045]waiting... 5 False [00:00:07.0439868]waiting... 6 False [00:00:08.0447972]waiting... 7 False [00:00:09.0456474]waiting... 8 False [00:00:10.0386241]fire abort [00:00:10.0388371]task finished [00:00:10.0459762]waiting... 9 True [00:00:11.0516456]waiting... 10 True

投稿2018/09/18 21:12

編集2018/09/19 15:10
testset

総合スコア221

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/09/19 00:37 編集

いやいや、引用されたのは Task の動いているスレッドを強制終了していいかどうかという話です。 スレッドプールを使うのでしていいわけがありません。 スレッドの強制終了という無茶苦茶をするのではなく、Task を終了すればいいだけです。 そのための CancellationTokenSource です。 スレッドは重いのでなるべく使わず、スレッドプールや Task を使ってください。 中でも主流は Task と async await です。 この質問は async を使いたくないという特殊な意図が質問者にあるので私は回答していません。 その考え、こだわりを見て「説明長くなりそう」と思ったからです。
testset

2018/09/19 15:11 編集

Task上でスレッドを強制終了するのはNGである認識です。 本回答が有害と思われるのでしたら、回答を削除させていただきます。 なお、釈明ですが、CancellationTokenSource で中断できなかったので、上記回答としました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問