我有一个Windows服务(.NET 4)定期处理队列,例如每15分钟一次。我使用System.Threading.Timer
,当服务开始每X毫秒触发一次回调时设置{{1}}。通常每次运行需要几秒钟而且永远不会发生冲突,但如果我不能假设那么 - 那么如果处理正在进行中,我希望下一次运行立即退出。
这可以通过锁定,易失性bool或监视器轻松解决,但实际上在这种情况下使用的是什么,或者只是一般的首选选项?
我发现其他帖子几乎可以回答这种情况(例如Volatile vs. Interlocked vs. lock),但需要一些建议,将其扩展到Timer示例并立即退出。
答案 0 :(得分:6)
您不需要任何锁定,您应该从计时器委托中重新安排下一个计时器执行。这应该确保100%没有重叠。
在计时器的事件处理程序调用{{1}}结束时,计时器将在timer.Change(nextRunInMilliseconds, Timeout.Infinite)
之后仅触发一次。
示例:
nextRunInMilliseconds
答案 1 :(得分:1)
好吧,他们中的任何一个都能胜任这项工作。 Monitor
通常通过lock
非常简单,但在这种情况下你不能使用lock
,因为你需要指定零超时;因此,最简单的方法可能是CompareExchange
:
private int isRunning;
...
if(Interlocked.CompareExchange(ref isRunning, 1, 0) == 0) {
try {
// your work
} finally {
Interlocked.Exchange(ref isRunning, 0);
}
}
对Monitor
做同样的事情是:
private readonly object syncLock = new object();
...
bool lockTaken = false;
try {
Monitor.TryEnter(syncLock, 0, ref lockTaken);
if (lockTaken) {
// your work
}
} finally {
if(lockTaken) Monitor.Exit(syncLock);
}
答案 2 :(得分:0)
我认为,如果您发现需要同步计时器委托 - 您做错了,Timer
可能不是您要使用的类。 Imho更好:
1)要么保留Timer
,要么将间隔值增加到可以安全假设的点,即线程没有问题,
2)或删除Timer
并使用简单的线程代替。你知道,比如:
var t = new Thread();
t.Start(() =>
{
while (!_stopEvent.WaitOne(100))
{
..........
}
});