Я создаю базовый класс службы 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!). Никакие задачи не выполняются, и он остается на этом номере навсегда!
Во-первых, я не понимаю, как это число может быть больше 10, хотя ThreadPool.SetMaxThreads
должно ограничивать его 10?
Во-вторых, даже если бы я не установил максимальное количество потоков, я ожидал бы, что блок finally PollWrapper в конечном итоге вернет счетчик к 0. Если счетчик остается больше 0, это можно объяснить только с помощью наконец, блок не выполняется, верно !? Как это возможно?
И, наконец, не могли бы вы предложить другой способ ограничения опроса числом возможных одновременных запущенных потоков фиксированным числом (.NET 3.5)?
Большое спасибо.
UPDATE:
После прочтения комментариев Яхии о повторном входе и SetMaxThread я изменил 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();
}
}