从Threading.Timer只调用一次方法

Ric*_*ard 2 c# multithreading .net-3.5

我有一个频繁激发的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);
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

spe*_*der 5

你可以做这样的事情并完全避免计时器。

void Main()
{
    RunPeriodicAsync();
}
async Task RunPeriodicAsync()
{
    while(true)
    {
        await Task.Delay(someTimeSpan);
        DoTheThing();
        if(!goAgain)break;
    }

}
Run Code Online (Sandbox Code Playgroud)

或者如果您需要支持取消:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

没有 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);
}
Run Code Online (Sandbox Code Playgroud)


Han*_*ant 5

没有什么可以解决这个问题.请注意,使用是一个非常糟糕的主意,当回调持续​​花费太多时间时,它会使您的线程池爆炸.机器加载时很容易发生这种情况.使用Monitor.TryEnter()是安全的替代方案.肯定也不漂亮,你会随意丢失回调.

如果你只是将句点参数设置为0,它就会变得更容易.因此,计时器只能勾选一次.现在,您可以自动确保无法重新输入回调.您所要做的就是在方法结束时调用Change()来重新启动计时器.您可以根据实际过期时间使用固定值或计算新的dueTime值,这两者都是合理的选择.