C# 使用带线程的锁。计时器
我有一个Windows服务应用程序,它使用C# 使用带线程的锁。计时器,c#,multithreading,locking,C#,Multithreading,Locking,我有一个Windows服务应用程序,它使用Threading.Timer和TimerCallback以特定的间隔执行一些处理。我需要将这个处理代码一次只锁定到一个线程 例如,启动服务并触发第一个回调,启动线程并开始处理。只要处理在下一次回调之前完成,这就可以正常工作。比如说,处理时间比平常稍长,当另一个线程正在处理时,TimerCallback会再次触发,我需要让该线程等待,直到另一个线程完成 以下是我的代码示例: static Timer timer; static object locker
Threading.Timer
和TimerCallback
以特定的间隔执行一些处理。我需要将这个处理代码一次只锁定到一个线程
例如,启动服务并触发第一个回调,启动线程并开始处理。只要处理在下一次回调之前完成,这就可以正常工作。比如说,处理时间比平常稍长,当另一个线程正在处理时,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
}
}
这样做安全吗?如果队列变得相当多,会发生什么?有更好的选择吗?如果可以让事件以固定的间隔触发(与当前代码以固定的间隔触发相反),那么您可以启动计时器,而无需使用句点,每次都可以排队等待新的回调,例如
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);
}
}
此代码告诉新创建的计时器立即启动,仅启动一次。在处理代码中,它完成工作,然后告诉计时器在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);
}
}
}
如果处理代码的执行时间超过10秒,则最糟糕的情况是每次调用新回调时都会浪费1个线程池线程(它们将在lock语句中等待)。如果您接受所有线程池线程HttpWebRequest、ASP.NET、异步委托调用。。。我会受苦的 我要做的是立即安排第一次回调。然后,如果确实需要每隔10秒调用DoSomething():
public void DoSomething ()
{
DateTime start = DateTime.UtcNow;
...
TimeSpan elapsed = (DateTime.UtcNow - start);
int due_in = (int) (10000 - elapsed.TotalMilliseconds);
if (due_in < 0)
due_in = 0;
timer.Change (due_in, Timeout.Infinite);
}
public void DoSomething()
{
DateTime start=DateTime.UtcNow;
...
时间跨度经过=(DateTime.UtcNow-start);
int due_in=(int)(10000-已用的.total毫秒);
如果(到期日<0)
到期日=0;
timer.Change(到期,超时,无限);
}
或者类似的东西。触发计时器的好主意从来没有这样想过。第二种情况,这是否意味着线程只是退出而不等待?是的,在第二种情况下,如果当前处理代码中有另一个线程,TryEnter将立即返回,因此它有效地跳过了该计时器间隔。太好了!我使用的是JavaScript中的第一个场景。不知道如何在C#中实现它。