Таймер и обработка исключений в службе Windows - PullRequest
1 голос
/ 11 октября 2011

У меня была странная проблема с приведенным ниже кодом.Я не понимаю, в чем именно проблема.Код ниже является частью службы Windows.Этот код вызывает одну функцию класса com для выполнения некоторой операции с очередью сообщений через фиксированный интервал.Я использовал System.threading.timer для этой цели.После запуска служба работает нормально некоторое время, но через некоторое время перестает работать.

using System;
using System.IO;
using System.ServiceProcess;
using System.Threading;
using CareMC.VBWrapper.RCWQueue;

namespace MSPQueueService
{
    public partial class MSPQueueService : ServiceBase
    {
        static System.Threading.Timer timer;
        const int TIMEOUTVALUE = 5000;
        private int isBusy = 0;
        public MSPQueueService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            try
            {
                AppendToLog("ONStart Begin");
                //Handle Elapsed event

                TimerCallback timerDelegate = new TimerCallback(OnElapsedTime);

                timer = new System.Threading.Timer(timerDelegate, null, TIMEOUTVALUE, TIMEOUTVALUE);
                //EVENT _objEvent = new EVENT();
                //_objEvent.ExecuteMSPQueue();
                AppendToLog("ONStart End");
            }
            catch (Exception ex)
            {
                string ErrorMessage = ex.Message.ToString();
                AppendToLog(ErrorMessage);
            }

        }

        private void OnElapsedTime(object state)
        {

            //If the isBusy value is 0 then replace it with 1 and continue otherwise it has already been incremented so we're already running

            //the handler so skip out

            if (Interlocked.CompareExchange(ref isBusy, 1, 0) != 0)
            {
                AppendToLog("OnElapsedTime is already running. isBusy=" + isBusy.ToString());
                return;
            }

            try
            {

                EVENT _objEvent = new EVENT();
                AppendToLog("Before Executing ExecuteMSPQueue function.");
                _objEvent.ExecuteMSPQueue();
                AppendToLog("After Executing ExecuteMSPQueue function.");
            }
            catch (Exception ex)
            {
                AppendToLog(ex.ToString());
            }
            finally
            {
                AppendToLog("Resetting  isBusy value to 0=");
                Interlocked.Exchange(ref isBusy, 0);
                AppendToLog("Value of   isBusy  after reset =" + isBusy);

            };

        }


}

Вот лог-файл с кодом

10/11 / 2011 4:15:03: перед выполнением функции ExecuteMSPQueue.

10 /11/2011 4:15:08 AM: OnElapsedTime уже запущен.

10/11 / 2011 4:15:13 AM: OnElapsedTime уже запущен.

10/11/11 2011 4: 15: 18 AM: OnElapsedTime уже запущен.

10/11 / 2011 4:15:19 AM: после выполнения функции ExecuteMSPQueue.

10/11/2011 4:15:28AM: OnElapsedTime уже запущен.

10/11 / 2011 4:15:33 AM: OnElapsedTime уже запущен.

10/11/11 2011 4:15:38 AM: OnElapsedTime установленуже запущен.

10/11 / 2011 4:15:43 AM: OnElapsedTime уже запущен.

10/11 / 2011 4:15:48 AM: OnElapsedTime уже запущен.

10/11 / 2011 4:15:53 ​​AM: OnElapsedTime уже запущен.

Это означает, что значение переменной IsBusy остается равным 1 и не сбрасывается в 0.просмотр кода возможен только в том случае, если есть исключение, которое не попадает в блок catch (возможно ли это?)

Пожалуйста, помогите мне.

Ответы [ 2 ]

1 голос
/ 11 октября 2011

Таймер сработает независимо от того, завершился или нет предыдущий прогон. Если OnElapsedTime занимает более 5 секунд, значение все равно будет равно 1, когда таймер снова запустится.

Делегат обратного вызова вызывается из потоков пула потоков, поэтому этот конкретный случай возможен.

Из MSDN:

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

EDIT:

Согласно комментарию, учитывая тот факт, что ваш блок finally никогда не выполняется, я предполагаю, что ваш поток, который вошел в журнал "После выполнения", все еще завис или заблокирован, либо в методе регистрации, либо возможно финализатор СОБЫТИЯ (если он есть). Вот где, вероятно, очень полезно поработать с отладчиком.

0 голосов
/ 11 октября 2011

Остерегайтесь метода ведения журнала, у вас могут быть параллельные проблемы, которые могут быть причиной проблем, с которыми вы столкнулись. В зависимости от ваших требований, я бы изменил дизайн вашего сервиса, используя Thread + Thread.Sleep ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...