首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何保持System.Timers.Timer在ElapsedEvent期间停止

如何保持System.Timers.Timer在ElapsedEvent期间停止
EN

Stack Overflow用户
提问于 2021-04-30 07:27:00
回答 3查看 116关注 0票数 1

我正在使用System.Timers.Timer,每隔x秒钟,我就需要在ElapsedEvent方法中执行一些任务。当我在ElapsedEvent方法中执行任务时,我希望停止计时器。但是,我有另一个方法可以启动计时器,它可以在ElapsedEvent运行时调用。我的代码如下所示:

代码语言:javascript
复制
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;
}

如何防止AnotherMethodElapsedEventTask中完成任务时启动计时器

EN

回答 3

Stack Overflow用户

发布于 2021-04-30 08:31:03

您可以添加一个变量来指示任务是否正在运行。最后,为了确保线程安全,当这个变量与lock一起使用时,您需要使用myTimer.Enabled

代码语言:javascript
复制
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;
            }
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2021-04-30 17:03:50

根据文档System.Timers.Timer类不是线程安全的,因此在没有同步的情况下,从多个线程中访问其Enabled属性是不安全的(这样做会导致未定义的行为)。Vernou的回答展示了如何通过使用锁来同步线程,但就我个人而言,试图使用一种显然被设计为可重入的机制来强制执行不重叠的执行策略,我有点紧张。因此,我的建议是放弃System.Timers.Timer,使用由Stephen的PauseTokenSource机制控制的异步循环:

代码语言:javascript
复制
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();
}

PauseTokenSourcePauseToken的控制器,这是一个与CancellationTokenSource/CancellationToken组合类似的概念。不同之处在于,CancellationTokenSource只能被取消一次,而PauseTokenSource可以暂停/取消多次。这个类包含在AsyncEx.Coordination包中。

MyClass公开一个终止异步循环的Complete方法和一个可以等待的Completion属性。在关闭程序之前await这个属性是一个好主意,给任何活跃的操作提供完成的机会。否则,该进程可能会在后台执行过程中被终止,并带来不可预知的后果。

票数 0
EN

Stack Overflow用户

发布于 2021-04-30 08:01:22

我会创建一个一次性计时器,然后您需要在计时器函数的末尾重新启动它。

代码语言:javascript
复制
myTimer = new System.Timers.Timer();
myTimer.AutoReset = false;


public void ElapsedEventTask(object source, ElapsedEventArgs e) {
  ...
  finally
  {
     myTimer.Start();
  }

}

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67329875

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档