保留中のタスクのスケジュールテーブルからのポーリングとそれらの実行を管理するために、Windowsサービスの基本クラスを構築しています。
Windowsサービスは、を使用しSystem.Timers.Timer
てスケジュールのテーブルポーリングを開始しています。
ThreadPool.SetMaxThread
タイマーを初期化する前に、を10に設定しています。
protected override void OnStart(string[] args)
{
ThreadPool.SetMaxThreads(10, 10);
this._Timer = new System.Timers.Timer();
this._Timer.Elapsed += new ElapsedEventHandler(PollWrapper);
this._Timer.Interval = 100;
this._Timer.Enabled = true;
}
タイマーによって呼び出されるデリゲートメソッドは、実行中のスレッドのカウントを保持するため、OnStop()メソッドで使用して、サービスを破棄する前に各スレッドが完了するのを待つことができます。
private void PollWrapper(object sender, ElapsedEventArgs e)
{
numberOfRunningThreads++;
try
{
this.Poll(sender, e);
}
catch (Exception exception)
{
//some error logging here
}
finally
{
numberOfRunningThreads--;
}
}
protected override void OnStop()
{
this._Timer.Enabled = false;
while (numberOfRunningThreads > 0)
{
this.RequestAdditionalTime(1000);
Thread.Sleep(1000);
}
}
多くの場合、Windowsサービス管理コンソールからサービスを停止しようとしても、サービスは停止しません。デバッグしてOnStop()メソッドにブレークポイントを追加すると、numberOfRunningThreadsが0より大きい数(多くの場合10より大きい!)でスタックしているためではないことがわかります。実行中のタスクはなく、その数に永久に留まります。
ThreadPool.SetMaxThreads
まず、10に制限する必要があるにもかかわらず、その数が10を超える可能性があることを理解していませんか?
次に、スレッドの最大数を設定しなかった場合でも、PollWrapperのfinallyブロックが最終的にカウントを0に戻すことを期待します。カウンターが0より大きいままの場合、finallyブロックでは説明できません。実行中ですよね!?それはどのように可能ですか?
そして最後に、ポーリングを固定数(.NET 3.5)の可能な同時実行スレッドの数に制限する別の方法を提案しますか?
どうもありがとう。
アップデート:
再入可能性とSetMaxThreadに関するYahiaのコメントを読んだ後、PollWrapperを変更して、生成される実行中のスレッドの最大数を常に制限するようにしました。投票が再入可能であることを確認します。
private void PollWrapper(object sender, ElapsedEventArgs e)
{
lock(this)
{
if(this.numberOfRunningThreads < this.numberOfAllowedThreads)
{
this.numberOfRunningThreads++;
Thread t = new Thread(
() =>
{
try
{
this.Poll(sender, e);
}
catch (Exception ex)
{
//log exception
}
finally
{
Interlocked.Decrement(ref this.numberOfRunningThreads);
}
}
);
t.Start();
}
}