Таймер повторного входа в Windows Service - PullRequest
3 голосов
/ 10 декабря 2011

Я хочу построить службу 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 ]

4 голосов
/ 11 декабря 2011

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

EDIT:

Я думаю, что имеет больше смысла использовать 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);
}

}

2 голосов
/ 11 декабря 2011

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

2 голосов
/ 11 декабря 2011

Если вы хотите просто пропустить вызов метода, пока предыдущий метод не закончил, просто используйте 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
    }

  }
2 голосов
/ 10 декабря 2011

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

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

Когда задача будет выполнена, включите таймер снова ... возможно, в предложении "Окончание".1005 *

...