C # WinService с управляемыми по таймеру операциями пула потоков - PullRequest
3 голосов
/ 20 января 2011

У меня есть класс службы Windows (унаследованный от ServiceBase), который во время создания предоставляется со списком объектов. Каждая операция описывает виртуальный метод DoWork ().
Задача класса Service - управлять всеми базовыми операциями, добавлять / удалять их в список во время выполнения и выполнять их метод DoWork () в потоке ThreadPool.
Каждая операция имеет объект System.Timers.Timer, который создается и запускается вместе с классом Operation. Каждая Операция предоставляет событие для оповещения управляющего класса о том, что его собственный таймер включен, и он должен запустить собственный метод DoWork () в потоке.

Класс TimedService связывает каждое прошедшее событие таймера с методом, который запрашивает поток из пула:

private void CheckOperationsList(object source, EventArgs e)
{
 try
  {
    foreach (Operation op in this._operationsList)
    {
      lock (this._operationsList)
      {
        op.TimerElapsed += new Operation.ElapsedEventHandler(this.RequestThreadFromPool);
      }
    }
  }
  catch (Exception ex) { this._ManEV.WriteError(this._serviceName, ex.Message); }
}  

И, конечно, метод RequestThreadFromPool (отправитель объекта, EventArgs e) делает следующее:

    ThreadPool.QueueUserWorkItem(new WaitCallback(((Operation)sender).DoWork), new object());  

Я получаю странное поведение от процессов. Я попытался реализовать фиктивную операцию с таймером, установленным на 10 секунд, который просто удерживает процессор занятым в течение пары секунд:

for (Int16 i = 0; i < Int16.MaxValue; i++)
  {
    for (short j = 0; j < short.MaxValue; j++)
    { }
  }  

Каждый раз, когда Операция запускается одна в очереди (я передаю Список только одному элементу Сервису), все нормально. Процесс порождает свой собственный поток, поддерживает процессор в течение нескольких секунд, а затем уходит.

Я реализовал более легкую версию метода-пустышки, описанного выше (в основном то же самое без внутреннего цикла), чтобы имитировать легкую нить.

Как только я получаю две или более операций в очереди (с разными таймерами!), Все потоки появляются три или четыре раза, а затем все останавливается.
Я вообще ничего не получаю. В Visual Studio похоже, что таймер каждой операции прекратил тикать - я не получаю вызовов на событие, я не получаю вызовов делегату, который должен обрабатывать событие; Каждый класс операций имеет свой собственный таймер и всегда обращается к нему через него. !

Я пытался отслеживать все перехватчики {} и пытался обернуть каждый метод DoWork () в попытку {}, но я не получаю никаких исключений.

Что меня озадачивает, так это то, что если я запускаю несколько одинаковых операций (то есть две, три длинные операции или две или три короткие операции), все работает как обычно. Похоже, что Событие исходит от другого класса, все запутано.

Я начинаю думать, что класс System.Timers.Timer является причиной всего вышесказанного - я пытался вызвать Stop () для таймера прямо перед вызовом Event, но безрезультатно. Я получаю 4-5 итераций каждого метода операции DoWork (), а затем все заканчивается.

edit Я забыл уточнить: каждая выполняемая мной операция наследуется от базовой операции. I.e:

public class TestLongOperation : Operation
{
  public TestLongOperation(double secondsInterval) : base(secondsInterval) { }
  public override void Work(object buh)
  {
    for (Int16 i = 0; i < Int16.MaxValue; i++)
    {
      for (short j = 0; j < short.MaxValue; j++)
      { }
  }
}

}

Есть предложения? Я могу предоставить больше кода, если выше не достаточно. Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 20 января 2011

У меня такое чувство, что таймер создает новый поток для каждого события тика, у меня была проблема с моим сервисом, из-за которого возникало множество потоков, если много обработки продолжалось с предыдущего тика, когда начинается следующий тик.

В итоге я полностью удалил таймер и заменил его на петлю.Затем в моей основной теме обработки я добавил Thread.sleep.Это тогда действует как таймер, но не продолжает порождать потоки.Кроме того, цикл не завершается, пока не закончится обработка.

Например:

(Main Thead)

bool running = true;

while (running)
{

  //do processing


  /sleep for 'timer' interval
  Thread.Sleep(interval)
}

это помогает вообще?

0 голосов
/ 20 января 2011

Несколько случайных мыслей:

Когда программа зависает, нажали ли вы кнопку «разрыв» и «проверь», находились ли вы в паре «заблокированных» строк.

Это таймеры? Если так, подключил обработчик событий перед включением таймера. Если нет, то возвращается ли ваша работа?

В обработчике таймера, почему вы создаете другой поток для выполнения работы? Таймер уже поместил его в новую ветку. Может быть, вы попали в исчерпание пула потоков? Если несколько обработчиков таймера запускаются и используют пул потоков, они зависнут в ожидании запуска рабочих потоков.

Чтение Свойство Timer.SynchronizingObject , чтобы увидеть, что Таймер может использовать ThreadPool.

...