Как иметь петлю в службе Windows без использования таймера

Я хочу вызвать метод бизнес-уровня из службы Windows (выполняется с использованием С# и .NET) через каждые 10 секунд. Однако я не хочу использовать событие Timer_Elapsed, поскольку он запускает другой поток/процесс, если первый поток/процесс все еще запущен. Мне просто нужен однопоточный подход, поскольку несколько вызовов одного и того же метода Business создают нежелательные осложнения.

Итак, я добавил цикл do-while в on_start. Я знаю, что это неверно, поскольку он порождает этот процесс, который становится сиротой, если служба отключена.

Как я могу подойти к этой проблеме?

С уважением, Чак

Ответ 1

В другом способе выполнения тайм-аута метод WaitHandle.WaitOne() предоставляет аргумент тайм-аута. Это очень хорошо работает в сервисе, поскольку позволяет реализовать необходимость остановки службы и периодического выполнения в одном вызове метода. Шаблон выглядит следующим образом:

    Thread Worker;
    AutoResetEvent StopRequest = new AutoResetEvent(false);

    protected override void OnStart(string[] args) {
        // Start the worker thread
        Worker = new Thread(DoWork);
        Worker.Start();
    }
    protected override void OnStop() {
        // Signal worker to stop and wait until it does
        StopRequest.Set();
        Worker.Join();
    }
    private void DoWork(object arg) {
        // Worker thread loop
        for (;;) {
            // Run this code once every 10 seconds or stop right away if the service 
            // is stopped
            if (StopRequest.WaitOne(10000)) return;
            // Do work...
            //...
        }
    }

Ответ 2

Используйте таймер, но как только вы введете метод обработчика таймера, отключите таймер, чтобы больше не возникало событий. Незадолго до выхода из обработчика снова включите таймер.

Ответ 3

Просмотрите эту дискуссию и, в частности, ответ jsw. Он предлагает механизм синхронизации для предотвращения множественных одновременных вызовов бизнес-логики. Просто отключить таймер в методе обработчика Elapsed не гарантируется, чтобы предотвратить параллельные вызовы, поскольку обработчик вызывается в отдельном потоке. Используйте блокировку, как предлагает jsw, и остановите таймер в синхронизированном блоке кода.

В качестве альтернативы вы можете использовать Timer и установить для свойства AutoReset значение false. Таким образом, событие Elapsed создается только один раз, и вы можете reset таймер вручную в конце метода обработчика.

Ответ 4

while(true)
    {
     ..do something
     Thread.sleep( some time or day);
    }

Ответ 5

    Thread thread;
    private void DoWork(object arg)
    {
        while (true)
        {
            // Run this code once every 20 seconds or stop if the service is stopped
            try
            {
                Thread.Sleep(20000);
                //Do work....
            }
            catch(ThreadInterruptedException)
            {
                return;
            }

        }
    }

    protected override void OnStart(string[] args)
    {
        // Start the thread
        thread = new Thread(DoWork);
        mWorker.Start();
    }

    protected override void OnStop()
    {
        // interrupt thread and wait until it does
        thread.Interrupt();
        thread.Join();
    }