我正在使用System.Timers.Timer,每隔x秒钟,我就需要在ElapsedEvent方法中执行一些任务。当我在ElapsedEvent方法中执行任务时,我希望停止计时器。但是,我有另一个方法可以启动计时器,它可以在ElapsedEvent运行时调用。我的代码如下所示:
class MyClass {
Timer myTimer;
public MyClass {
myTimer = new System.Timers.Timer();
// init timer code here...
}
public void ElapsedEventTask(object source, ElapsedEventArgs e) {
myTimer.Enabled = false;
try
{
// do my tasks
}
catch
{
...
}
finally
{
myTimer.Enabled = true;
}
}
}
public void AnotherMethod() {
// do some things
myTimer.Enabled = true;
}如何防止AnotherMethod在ElapsedEventTask中完成任务时启动计时器
发布于 2021-04-30 08:31:03
您可以添加一个变量来指示任务是否正在运行。最后,为了确保线程安全,当这个变量与lock一起使用时,您需要使用myTimer.Enabled:
class MyClass
{
object syncEnableRunning = new object();
bool running
Timer myTimer;
public void ElapsedEventTask(object source, ElapsedEventArgs e)
{
lock(syncEnableRunning)
{
running = true;
myTimer.Enabled = false;
}
try { /*do my tasks*/}
catch { ... }
finally
{
lock(syncEnableRunning)
{
myTimer.Enabled = true;
running = false;
}
}
}
public void AnotherMethod()
{
// do some things
lock(syncEnableRunning)
{
if(!running)
{
myTimer.Enabled = true;
}
}
}
}发布于 2021-04-30 17:03:50
根据文档,System.Timers.Timer类不是线程安全的,因此在没有同步的情况下,从多个线程中访问其Enabled属性是不安全的(这样做会导致未定义的行为)。Vernou的回答展示了如何通过使用锁来同步线程,但就我个人而言,试图使用一种显然被设计为可重入的机制来强制执行不重叠的执行策略,我有点紧张。因此,我的建议是放弃System.Timers.Timer,使用由Stephen的PauseTokenSource机制控制的异步循环:
class MyClass
{
private readonly CancellationTokenSource _cts;
private readonly PauseTokenSource _pts;
public Task Completion { get; private set; }
public MyClass(TimeSpan interval)
{
_cts = new CancellationTokenSource();
_pts = new PauseTokenSource();
_pts.IsPaused = true;
Completion = Task.Run(async () =>
{
try
{
while (true)
{
await _pts.Token.WaitWhilePausedAsync(_cts.Token);
var delayTask = Task.Delay(interval, _cts.Token);
/* Do my tasks */
await delayTask;
}
}
catch (OperationCanceledException)
when (_cts.IsCancellationRequested) { } // Ignore
});
}
public void Start() => _pts.IsPaused = false;
public void Stop() => _pts.IsPaused = true;
public void Complete() => _cts.Cancel();
}PauseTokenSource是PauseToken的控制器,这是一个与CancellationTokenSource/CancellationToken组合类似的概念。不同之处在于,CancellationTokenSource只能被取消一次,而PauseTokenSource可以暂停/取消多次。这个类包含在AsyncEx.Coordination包中。
MyClass公开一个终止异步循环的Complete方法和一个可以等待的Completion属性。在关闭程序之前await这个属性是一个好主意,给任何活跃的操作提供完成的机会。否则,该进程可能会在后台执行过程中被终止,并带来不可预知的后果。
发布于 2021-04-30 08:01:22
我会创建一个一次性计时器,然后您需要在计时器函数的末尾重新启动它。
myTimer = new System.Timers.Timer();
myTimer.AutoReset = false;
public void ElapsedEventTask(object source, ElapsedEventArgs e) {
...
finally
{
myTimer.Start();
}}
https://stackoverflow.com/questions/67329875
复制相似问题