C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

CancellationTokenによるスリープ

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■93434 / inTopicNo.1)  CancellationTokenによるスリープ
  
□投稿者/ tama (1回)-(2019/12/12(Thu) 09:25:33)

分類:[C#] 

2019/12/12(Thu) 09:27:20 編集(投稿者)
ManualResetEventとCancellationTokenを使って
処理の中断と再開を実装しています。

処理途中でスリープするのですがManualResetEvent.Reset();が発行された場合に
即座にスリープを抜けたいのですがどのような方法があるでしょうか。

while (!処理して正常終了フラグを返す)
{
      // 30秒スリープ、スリープ途中でキャンセルされた場合は例外発行
      if (CancellationToken.WaitHandle.WaitOne(30 * 1000))
      {throw new OperationCanceledException();}

      // ManualResetEvent.Reset();が発行された場合にスリープを即座に抜けて停止したい
      // ManualResetEvent.Reset();、ManualResetEvent.Set();が発行されれば即座に次処理を行いたい
}

引用返信 編集キー/
■93437 / inTopicNo.2)  Re[1]: CancellationTokenによるスリープ
□投稿者/ KOZ (70回)-(2019/12/12(Thu) 09:45:47)
No93434 (tama さん) に返信
> 処理途中でスリープするのですがManualResetEvent.Reset();が発行された場合に
Reset でなくて Set ですよね?

> 即座にスリープを抜けたいのですがどのような方法があるでしょうか。

MS のサイトに WaitHandle.WaitAny を使ったサンプルがあります。

「方法: 待機ハンドルがあるキャンセル要求を待機する」
https://docs.microsoft.com/ja-jp/dotnet/standard/threading/how-to-listen-for-cancellation-requests-that-have-wait-handles

引用返信 編集キー/
■93443 / inTopicNo.3)  Re[2]: CancellationTokenによるスリープ
□投稿者/ tama (2回)-(2019/12/12(Thu) 12:22:22)
ご回答ありがとうございます。
以下のコードを記述してみたのですが、EventWaitHandle.WaitAnyの戻り値に
WaitHandle.WaitTimeoutが戻ってこず困っています。
ループ中にManualResetEvent.Reset();ManualResetEvent.Start();
(中断・再開すると)するとタイムアウトが発生するのですが・・・
EventWaitHandle.WaitAnyはWaitHandleに何らかのイベントが発生しないと
タイムアウトとすることができないのでしょうか。

私のEventWaitHandle.WaitAnyの使い方がそもそも間違っているような気もします。。。
よろしくお願いいたします。

if (!MainProcess()) 
// メインプロセスでエラーが発生した場合は30秒待ってから再度メインプロセスを実行
	while (true)
	{                                    
	    int eventThatSignaledIndex = EventWaitHandle.WaitAny(new WaitHandle[] { ManualResetEvent, CancellationToken.WaitHandle }, 30 * 1000);

	    // 一時停止の場合は無限に待つ
	    ManualResetEvent.WaitOne(-1);

	    // タスクがキャンセルされている場合は例外発行
	    CancellationToken.ThrowIfCancellationRequested();
	                                        
	    if (eventThatSignaledIndex == WaitHandle.WaitTimeout)
	    {
	        // 30秒経過した場合はメインプロセス実行
	        if (MainProcess())
	        {
	            break; // 正常終了の場合は終了
	        }
	    }
	}
}

引用返信 編集キー/
■93448 / inTopicNo.4)  Re[3]: CancellationTokenによるスリープ
□投稿者/ KOZ (72回)-(2019/12/12(Thu) 13:01:11)
No93443 (tama さん) に返信

EventWaitHandle.WaitAny の戻り値を確認してから次の動作を行ってください。

    int eventThatSignaledIndex = EventWaitHandle.WaitAny(new WaitHandle[] { ManualResetEvent, CancellationToken.WaitHandle }, 30 * 1000);
    switch (eventThatSignaledIndex) {
        case 0:
            ManualResetEvent.Reset(); // AutoResetEvent ならリセットの必要なし
            // ManualResetEvent がセットされたときの処理
            break;
        case 1:
            // タスクがキャンセルされたときの処理
            break;
        default:
            // タイムアウトの処理
            break;
    }


引用返信 編集キー/
■93452 / inTopicNo.5)  Re[4]: CancellationTokenによるスリープ
□投稿者/ tama (3回)-(2019/12/12(Thu) 13:12:14)
お忙しいところ、ありがとうございます。
無事実現できました。
とても悩んでいたので感謝いたします。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ