繁体   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