如果前一个线程仍然忙,如何让Timer跳过勾选

gil*_*lyb 14 c# multithreading windows-services timer

我创建了一个Windows服务,它应该每隔60秒检查数据库中的某个表以获取新行.对于添加的每个新行,我需要在服务器上进行一些繁重的处理,有时可能需要超过60秒.

我在我的服务中创建了一个Timer对象,每隔60秒就会调用一次,并调用所需的方法.
由于我不想在处理找到的新行时勾选此计时器lock { },因此我将该方法包装在一个块中,因此其他线程无法访问此方法.

它看起来像这样:

Timer serviceTimer = new Timer();
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();

void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    lock (this)
    {
        // do some heavy processing...
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想知道 -
如果我的计时器滴答,并在数据库上发现了很多新行,现在处理将花费超过60秒,下一个滴答将不会进行任何处理,直到前一个完成.这就是我想要的效果.

但现在,serviceTimer_Elapsed方法会在第一次处理完成后立即关闭,还是会等待计时器再次打勾.

我想要发生的是 - 如果处理需要超过60秒,那么计时器会注意到线程被锁定,再等待60秒再次检查,这样我就永远不会陷入有线程队列的情况等待前一个完成.

我怎样才能完成这个结果?
这样做的最佳做法是什么?

谢谢!

Stu*_*tLC 21

您可以尝试在处理期间禁用计时器,例如

// Just in case someone wants to inherit your class and lock it as well ...
private static object _padlock = new object();
try
{
  serviceTimer.Stop(); 

  lock (_padlock)
    { 
        // do some heavy processing... 
    } 
}
finally
{
  serviceTimer.Start(); 
}
Run Code Online (Sandbox Code Playgroud)

编辑:OP没有指定重入是否仅由计时器引起或者服务是否是多线程的.假设后者,但如果前者然后锁定应该是不必要的,如果计时器停止(AutoReset或手动)

  • 不要使用`lock(this)` - http://stackoverflow.com/questions/251391/why-is-lockthis-bad (11认同)
  • 将autoreset设置为false会更容易,然后我们不需要锁定任何东西 (3认同)

Ani*_*Ani 20

在这种情况下,您不需要锁.在启动之前设置timer.AutoReset = false.完成处理后,在处理程序中重新启动计时器.这将确保计时器每个任务 60秒触发.

  • +1我从来不知道有一个名为Autoreset的属性 (2认同)

Sco*_*ain 7

快速检查它是否正在运行.如果它正在运行,它将跳过此事件并等待下一个事件触发.

Timer serviceTimer = new Timer();
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
bool isRunning = false;
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    lock (this)
    {
        if(isRunning)
            return;
        isRunning = true;
    }
    try
    {
    // do some heavy processing...
    }
    finally
    {
        isRunning = false;
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*ndy 7

其他答案的类似变化,允许计时器保持滴答,只有在可以获得锁定时才能完成工作,而不是停止计时器.

把它放在经过的事件处理程序中:

if (Monitor.TryEnter(locker)
{
    try
    {
        // Do your work here.
    }
    finally
    {
        Monitor.Exit(locker);
    }
}
Run Code Online (Sandbox Code Playgroud)