从线程中只调用一次方法.计时器

本文关键字:一次 方法 计时器 线程 调用 | 更新日期: 2023-09-27 17:59:21

我有一个系统。线程。定时器经常触发(为了简单起见,我们说每秒钟一次),在回调中,我需要调用一个Action(它是通过构造函数传入的,所以位于另一个类中),在其中我进行一些处理(假设它需要2秒以上),我该如何防止我的处理逻辑被多次调用?看来锁定()在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);
}

谢谢!

从线程中只调用一次方法.计时器

必须解决这个问题并没有什么好处。请注意,使用是一个非常糟糕的主意,当回调持续花费太多时间时,它会使线程池爆炸。当机器装载时,这种情况很容易发生。使用Monitor。TryEnter()是安全的替代方法。当然也不漂亮,你会随意失去回拨。

如果您简单地将句点参数设置为0,那么检查就容易多了。因此计时器只能滴答作响一次。现在,您自动有了一个硬保证,即不能重新输入回调。您所要做的就是在方法结束时调用Change()来重新启动计时器。您可以使用固定值,也可以根据实际过期时间计算新的dueTime值,这两者都是合理的选择。

你可以这样做,完全避免定时器。

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();
    }
}

如果没有async/await,您可以:

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);
}

您可以使用布尔标志来防止重入:

    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;
    }