【问题标题】:How to ensure timer is fully paused?如何确保计时器完全暂停?
【发布时间】:2016-12-08 00:43:20
【问题描述】:

假设我们将此事件附加到计时器事件处理程序。

private void TimerTick(object sender, ElapsedEventArgs e)
{
    if(_gaurd) return;
    lock (this) // lock per instance
    {
        _gaurd = true;
        if (!_timer.Enabled) return;

        OnTick(); // somewhere inside here timer may pause it self.

        _gaurd = false;
    }
}

现在有两件事可以暂停这个计时器。一是来自 UI 线程的用户请求,二是可以自行暂停的计时器。

如果计时器自行暂停我们可以保证暂停将在我们继续之前完成。

timer.Stop();
OnPause(); // timer must be paused because OnPause() is not thread safe.

但如果用户请求定时器暂停,请求来自另一个线程,我们不能保证定时器是否完全暂停。

timer.Stop();
OnPause(); // timer event may be still inside OnTick() and may conflict with OnPause()

----------------------------------------------- -------------------------------------------------- ------

所以我正在寻找一种方法来使这个线程安全。这是我迄今为止尝试过的,但我不确定这是否适用于所有情况。

它看起来不错,但想确定是否有任何我不知道的地方。或者也许想知道是否有更好的方法使这个进程线程安全。

我试图将用户请求与计时器的内部工作分开。因此我有 两个 暂停计时器的方法。

public class Timer
{
    internal void InternalStop() // must be called by timer itself.
    {
        timer.Pause(); // causes no problem
    }

    public void Stop() // user request must come here. (if timer call this deadlock happens)
    {
        InternalStop();
        lock (this) // reference of timer
        {
            // do nothing and wait for OnTick().
        }
    }
}

这不是实际代码,但行为相同。它应该说明这个类不是线程安全的。 :

public class WorkingArea
{
    private List<Worker> _workers;

    public void OnTick()
    {
        foreach(var worker in _workers)
        {
            worker.Start();
        }

        if(_workers.TrueForAll(w => w.Ends))
        {
            PauseTimer();
        }
    }

    public void OnPause() // after timer paused
    {
        foreach(var Worker in _workers)
        {
            worker.Stop();
        }
    }
}

【问题讨论】:

  • 您需要提供minimal reproducible example
  • 我不确定我是否在关注。 暂停计时器并不重要,总有可能出现竞争条件。但是,您已经锁定了 Tick 方法 - 它应该在任何情况下都可以工作 - 是否暂停。
  • 你能提供minimal reproducible example吗?
  • @Enigmativity 我试图提供。你看我最后一堂课不是线程安全的。 Worker.Start();Worker.Stop(); 冲突
  • @M.kazemAkhgary - 这不是minimal reproducible example。我应该能够复制、粘贴和运行您的代码以查看您的错误或问题。

标签: c# multithreading timer ui-thread


【解决方案1】:

我的计时器已经是线程安全的。

这完全是因为我不知道Re-entrant locks

因此,如果来自另一个线程的用户请求暂停计时器,lock 将正常工作并会一直阻塞直到计时器完全暂停。

如果计时器在内部暂停它自己,它不会处理锁定。因为它在同一个线程中获得了锁。

public class Timer
{
    private timer = new System.Timers.Timer();

    private bool _guard = false;

    // stops the timer and waits until OnTick returns and lock releases.
    // timer can safely pause it self within OnTick.
    // if user request to pause from another thread, full pause is ensured
    public void Stop()       
    {
        timer.Pause();
        lock (this) // reference of timer. it wont dead lock
        {
            // do nothing and wait for OnTick().
        }
    }

    private void TimerTick(object sender, ElapsedEventArgs e)
    {
        if(_gaurd) return;
        lock (this) // lock per instance
        {
            _gaurd = true;
            if (!_timer.Enabled) return;

            OnTick(); // somewhere inside here timer may pause it self.

            _gaurd = false;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 2012-06-06
    • 2016-11-10
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    相关资源
    最近更新 更多