Windows 服务中的可重入定时器

发布于 2024-12-20 22:48:52 字数 1798 浏览 2 评论 0原文

我想构建一个Windows服务,它应该在不同的时间执行不同的方法。这根本与准确性无关。 我使用 system.timers.timer,并使用计数器调节要在事件处理程序方法内执行的不同方法。到目前为止一切正常。

所有方法都访问 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++;
             }
     }   

提前非常感谢!
非常感谢任何帮助!

I want to build a windows Service, which should execute different methods at different times. Its not about accuracy at all.
Im using a system.timers.timer, and regulate the different methods to be executed within the Eventhandler-method with counters. Thats working allright that far.

All of the methods are accessing a COM-port, making it neccessary to grant acceess-rights to only one method at a time. But since the methods can take some time to finish, the timer might tick again and want to execute another method while the COM-port is still being occupied. In this case, the event can and should just be dismissed.

Simplified down to one method, my elapsedEventHandler-method looks something like the following (try-catch and the different methods excluded here)

Note: While this is running perfectly on my Win7 x64, it struggles on a Win7 x86 machine with pretty much the very same software installed, whenever the method to be executed takes a long time. The timer wont tick any more, no Exception is thrown. Nothing! my question now is: Am I doing the part with access-control and the timer right, so that i can focus on other things? Im just not that familiar with timers and especially threading

     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++;
             }
     }   

Thank you very much in advance!
Any help is greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

佞臣 2024-12-27 22:48:52

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

}

I would recommend using System.Threading.Timer for this functionality. You can disable the timer when it executes, process your data, then re-enable the timer.

EDIT:

I think it makes more sense to use System.Threading.Timer because there isn't really a reason you need to drop the timer on a design surface, which is pretty much the only reason to use System.Timers.Timer. I really wish MS would remove it anyways, it's wrapping System.Threading.Timer which isn't all that difficult to use in the first place.

Yes, you do risk a problem with re-entrancy which is why I specified to change the timeout toTimeout.Infinite. You won't have this re-entrancy problem if you construct the timer with 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);
}

}

清泪尽 2024-12-27 22:48:52

如果您想在上一个方法未完成时跳过方法调用,只需在调用您的方法之前使用 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
    }

  }

If you want just skip method invocation while previous method didn't finish just use Monitor.TryEnter(lockObject) before calling your method.

EDIT:
Here's an example -

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
    }

  }
乞讨 2024-12-27 22:48:52

您可以尝试以下操作:

当计时器触发时,禁用计时器。

任务完成后,重新启用计时器...可能在 Final 子句中。

You can try this:

When the timer fires, disable the timer.

When the task is complete, re-enable the timer...possibly in the Finally clause.

雨落星ぅ辰 2024-12-27 22:48:52

在进行初始检查时,您正确使用CompareExchange 来测试和设置m_synchPoint 字段。您错误使用直接赋值在方法结束时将值重置为 0。您应该使用 Interlocked.Exchange 来将该值重置为 0。附注,您还应该将 m_synchPoint 更改为实例字段 - 它不应该是静态的。

You correctly use CompareExchange to test and set the m_synchPoint field when doing the initial check. You incorrectly use direct assignment to reset the value to 0 at the end of the method. You should use Interlocked.Exchange instead to reset the value to 0. As a side note, you should also change m_synchPoint to an instance field -- it should not be static.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文