簡體   English   中英

Windows服務中的重入計時器

[英]Reentrant Timer in 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++;
             }
     }   

提前非常感謝您!
任何幫助是極大的贊賞!

我建議使用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);
}

}

您可以嘗試以下方法:

當計時器啟動時,禁用計時器。

任務完成后,重新啟用計時器...可能在Final子句中。

如果您只想跳過方法調用而前一個方法還沒有完成,則在調用方法之前使用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
    }

  }

進行初始檢查時,您可以正確地使用CompareExchange來測試和設置m_synchPoint字段。 錯誤地使用直接分配將方法結尾處的值重置為0。 您應該改用Interlocked.Exchange將值重置為0。此外,還應將m_synchPoint更改為實例字段-它不應為靜態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM