Таймер повторного входа в Windows Service

Я хочу создать службу Windows, которая должна выполнять разные методы в разное время. Дело совсем не в точности. Я использую system.timers.timer и регулирую различные методы, которые будут выполняться внутри Eventhandler-метода с помощью счетчиков. Это работает хорошо, что далеко.

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

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

Примечание. Хотя он отлично работает на моем Win7 x64, он борется на компьютере с Win7 x86, на котором установлено почти то же самое программное обеспечение, всякий раз, когда выполняемый метод занимает много времени. Таймер больше не тикает, исключение не выбрасывается. Ничего такого! мой вопрос сейчас: я делаю часть с контролем доступа и таймером, чтобы я мог сосредоточиться на других вещах? Я просто не знаком с таймерами и особенно с потоками

     private static int m_synchPoint=0;
     private System.Timers.Timer timerForData = null;

    public MyNewService()
    {

        timerForData = new System.Timers.Timer();
        timerForData.Interval = 3000;
        timerForData.Elapsed += new ElapsedEventHandler(Timer_tick);
    }
    //Initialize all the timers, and start them
    protected override void OnStart(string[] args)
    {

        timerForData.AutoReset = true;
        timerForData.Enabled = true;
        timerForData.Start();
    }

    //Event-handled method
    private void Timer_tick(object sender, System.Timers.ElapsedEventArgs e)
    {
            ////safe to perform event - no other thread is running the event?                      
            if (System.Threading.Interlocked.CompareExchange(ref m_synchPoint, 1, 0) == 0)

            {
             //via different else-ifs basically always this is happening here, except switching aMethod,bMethod...
             processedevent++; 
             Thread workerThread = new Thread(aMethod);
             workerThread.Start();
             workerThread.Join(); 
             m_synchPoint=0;
             }
             else
             {
              //Just dismiss the event
              skippedevent++;
             }
     }   

Заранее большое спасибо!
Любая помощь очень ценится!

4 ответа

Решение

Если вы хотите просто пропустить вызов метода, в то время как предыдущий метод не закончился, просто используйте Monitor.TryEnter(lockObject) перед вызовом вашего метода.

РЕДАКТИРОВАТЬ: Вот пример -

public class OneCallAtATimeClass
{

    private object syncObject;

    public TimerExample()
    {
      syncObject = new object();
    }

    public void CalledFromTimer()
    {    
      if (Monitor.TryEnter(syncObject);)
      {
        try
        {
          InternalImplementation();
        }
        finally
        {
          Monitor.Exit(syncObject);
        }
      }    
    }

    private void InternalImplementation()
    {
      //Do some logic here
    }

  }

Я бы порекомендовал использовать System.Threading.Timer для этой функциональности. Вы можете отключить таймер при его запуске, обработать данные, а затем снова включить таймер.

РЕДАКТИРОВАТЬ:

Я думаю, что имеет больше смысла использовать System.Threading.Timer потому что на самом деле нет причины, по которой вам нужно бросать таймер на поверхность проекта, что является практически единственной причиной использования System.Timers.Timer, Я бы очень хотел, чтобы MS все равно удалила System.Threading.Timer который не так уж сложно использовать в первую очередь.

Да, вы рискуете проблемой с повторным входом, поэтому я указал изменить время ожидания наTimeout.Infinite, Вы не будете иметь эту проблему повторного входа, если вы создадите таймер с Timeout.Infinite,

public class MyClass
{
    private System.Threading.Timer _MyTimer;

public MyClass()
{
    _MyTimer = new Timer(OnElapsed, null, 0, Timeout.Infinite);
}

public void OnElapsed(object state)
{
    _MyTimer.Change(Timeout.Infinite, Timeout.Infinite);
    Console.WriteLine("I'm working");
    _MyTimer.Change(1000, Timeout.Infinite);
}

}

Вы можете попробовать это:

Когда таймер срабатывает, отключите таймер.

Когда задача будет завершена, снова включите таймер... возможно, в предложении "Наконец".

Вы правильно используете CompareExchange проверить и установить m_synchPoint поле при выполнении начальной проверки. Вы неправильно используете прямое назначение, чтобы сбросить значение до 0 в конце метода. Вместо этого вы должны использовать Interlocked.Exchange, чтобы сбросить значение до 0. Как примечание, вы также должны изменить m_synchPoint на поле экземпляра - оно не должно быть статическим.

Другие вопросы по тегам