我有一个频繁触发的System.Threading.Timer(为了简单起见,让我们说每一秒),在CallBack中我需要调用一个Action(通过构造函数传入,所以坐在另一个类中) )我在其中进行一些处理(让我们说需要2秒以上),如何防止多次调用处理逻辑?似乎lock()在Action调用中不起作用? 我使用的是.net 3.5。
public TestOperation(Action callBackMethod)
{
this.timer = new System.Threading.Timer(timer_Elapsed, callbackMethod, timerInterval, Timeout.Infinite);
}
private void timer_Elapsed(object state)
{
Action callback = (Action) state;
if (callback != null)
{
callback();
}
}
// example of the callback, in another class.
private void callBackMethod()
{
// How can I stop this from running every 1 second? Lock() doesn't seem to work here
Thread.Sleep(2000);
}
谢谢!
答案 0 :(得分:5)
没有必要解决这个问题。请注意,使用 lock 是一个非常糟糕的主意,当回调持续花费太多时间时,它会使您的线程池爆炸。机器加载时很容易发生这种情况。使用Monitor.TryEnter()是安全的替代方案。绝对不是很漂亮,你随意地会失去回调。
如果您只是将 period 参数设置为0,那么它就会变得更容易了。因此,计时器只能勾选一次。现在,您可以自动确保无法重新输入回调。您所要做的就是在方法结束时调用Change()来重新启动计时器。您可以根据实际过期时间使用固定值或计算新的 dueTime 值,这两者都是合理的选择。
答案 1 :(得分:3)
你可以这样做,完全避开计时器。
void Main()
{
RunPeriodicAsync();
}
async Task RunPeriodicAsync()
{
while(true)
{
await Task.Delay(someTimeSpan);
DoTheThing();
if(!goAgain)break;
}
}
或者如果您需要支持取消:
void Main()
{
var cts=new CancellationTokenSource();
RunPeriodicAsync(cts.Token);
//sometime later
cts.Cancel();
}
async Task RunPeriodicAsync(CancellationToken ct)
{
while(!ct.IsCancellationRequested)
{
await Task.Delay(1000);
DoTheWork();
}
}
击> <击> 撞击>
没有异步/等待你可以:
System.Threading.Timer timer;
void Main()
{
RunActionAfter(() => DoTheWork(), 2000);
}
void RunActionAfter(Action action, int period)
{
//Timeout.Infinite means the timer runs only once.
timer = new Timer(_ => action(), null, 2000, Timeout.Infinite);
}
void DoTheWork()
{
Console.WriteLine("!!!");
//then maybe
RunActionAfter(() => DoTheWork(),2000);
}
答案 2 :(得分:0)
您可以使用布尔标志来防止重入:
bool executing;
public TestOperation(Action callBackMethod)
{
this.timer = new System.Threading.Timer(timer_Elapsed, callbackMethod, timerInterval, Timeout.Infinite);
}
private void timer_Elapsed(object state)
{
if(executing)
return;
Action callback = (Action) state;
if (callback != null)
{
executing = true;
callback();
}
}
// example of the callback, in another class.
private void callBackMethod()
{
// How can I stop this from running every 1 second? Lock() doesn't seem to work here
Thread.Sleep(2000);
executing = false;
}