.NET
.NET ソフトウェア フレームワークに基づく Microsoft テクノロジ。
82 件の質問
このブラウザーはサポートされなくなりました。
Microsoft Edge にアップグレードすると、最新の機能、セキュリティ更新プログラム、およびテクニカル サポートを利用できます。
System.Threading.Timerで処理を行なっているシステムで、PCが高負荷になった際に2回実行されてしまう事象が発生しています。
本来は1分回に1回タイマーイベントを通知するように開発していますが、高負荷だとまれにタイマーイベントが2回通知されます。
本事象について、原因と解決策をご教示ください。
System.Threading.Timerのcallbackはスレッドプールで実行され、かつそのスレッドは一つだけではありません。 前のcallbackの処理が終わる前にperiodで指定した時間間隔が経過した場合、別のスレッドで次のcallbackを呼び出します。
System.Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} タイマーを作ったスレッドのID= {System.Threading.Thread.CurrentThread.ManagedThreadId}");
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((o) =>
{
bool isThreadPool = System.Threading.Thread.CurrentThread.IsThreadPoolThread;
bool isBackground = System.Threading.Thread.CurrentThread.IsBackground;
System.Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} タイマーのコールバックが実行されているスレッドのID= {System.Threading.Thread.CurrentThread.ManagedThreadId}\tIsThreadPool={isThreadPool}\tIsBackground={isBackground}");
System.Threading.Thread.Sleep(2000); //重い処理としてスレッドをブロック
}, null, 1000, 1000);
System.Threading.Thread.Sleep(-1);
これが問題ならば、コンストラクタまたは、Changeのperiod引数をSystem.Threading.Timeout.Infiniteにして1回だけ呼ばれるようにしておいて、callbackの最後に次の呼び出し時間を登録しなおすようにしてください。
System.Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} タイマーを作ったスレッドのID= {System.Threading.Thread.CurrentThread.ManagedThreadId}");
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((o) =>
{
bool isThreadPool = System.Threading.Thread.CurrentThread.IsThreadPoolThread;
bool isBackground = System.Threading.Thread.CurrentThread.IsBackground;
System.Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} タイマーのコールバックが実行されているスレッドのID= {System.Threading.Thread.CurrentThread.ManagedThreadId}\tIsThreadPool={isThreadPool}\tIsBackground={isBackground}");
System.Threading.Thread.Sleep(2000); //重い処理としてスレッドをブロック
timer.Change(1000, System.Threading.Timeout.Infinite); //必要なら次の時間を計算する
}, null, 1000, System.Threading.Timeout.Infinite);
System.Threading.Thread.Sleep(-1);