使用带有Threading.Timer的锁

Jam*_*mes 14 c# multithreading locking

我有一个Windows服务应用程序,它使用a Threading.Timer和a TimerCallback以特定间隔进行一些处理.我需要一次将此处理代码锁定为仅1个线程.

因此,例如,启动服务并触发第一个回调并启动线程并开始处理.只要在下一次回调之前完成处理,这就可以正常工作.所以说比如说处理比平常花费的时间稍长,并且在另一个线程正在处理时再次触发TimerCallback,我需要让该线程等到另一个线程完成.

这是我的代码示例:

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      lock(locker)
      {
           // my processing code
      }
}
Run Code Online (Sandbox Code Playgroud)

这是一种安全的方法吗?如果队列变得相当大,会发生什么?有更好的选择吗?

Gre*_*ech 35

如果您可以使用它们之间的恒定间隔触发事件(与以恒定间隔触发它们的当前代码相反),那么您可以在没有句点的情况下启动计时器,并且每次排队新的回调时,例如

static Timer timer;

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, Timeout.Infinite);
}

public void DoSomething()
{
      try
      {
           // my processing code
      }
      finally
      {
          timer.Change(10000, Timeout.Infinite);
      }
}
Run Code Online (Sandbox Code Playgroud)

此代码告诉新创建的计时器立即触发,仅一次.在处理代码中,它完成工作,然后告诉计时器在10秒内再次触发,仅一次.因为定时器现在不是定期触发但是通过其回调方法重新启动,所以回调保证是单线程的,没有队列.

如果你想保持一个恒定的间隔,那么它有点棘手,因为你必须决定如果处理开始花费的时间超过定时器间隔该怎么办.一种选择是执行您当前正在执行的操作,但这实际上会导致大量排队的线程和最终的线程池饥饿.另一种选择是,如果已经有一个回调,则简单地丢弃回调,例如

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      if (Monitor.TryEnter(locker))
      {
           try
           {
               // my processing code
           }
           finally
           {
               Monitor.Exit(locker);
           }
      }
}
Run Code Online (Sandbox Code Playgroud)