c# - System.Timers.Timer.Enabled 属性线程安全吗,是否可以从计时器的 Elapsed 事件访问它?

标签 c# multithreading timer thread-safety

我有一个 Elapsed 方法,其中有一个 while 循环。如果定时器被另一个线程禁用/停止,我希望这个循环停止。为此,我可以依赖 Elapsed 方法中计时器的 Enabled 属性吗,还是应该创建一个“volatile bool timerEnabled”变量来确定。我的测试表明它没问题,但我想在将其投入生产之前确定这一点。

这就是我想要实现的(不是实际代码,而是接近)

private volatile bool isElapsedAlreadyRunning

void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    if (!isElapsedAlreadyRunning)   // to prevent reentrance
    {
        isElapsedAlreadyRunning = true;
        try 
        {
            while (myTimer.Enabled && some other condition)
            {
                do stuff
            }
        }
        finally
        {
            isElapsedAlreadyRunning = false;
        }
    }
}

myTimer.Start() and myTimer.Stop() are in other methods that can be called frrom other threads

我正在使用 System.Timers.Timer 类

如果您有任何其他意见或看到此设计中的任何缺陷,请随时发表评论:)

谢谢


编辑:

伙计,线程很难。基于答案和其他 stackoverflow 问题 ( this answer particularly ) 这将是这样做的方式(我希望这次没问题)

public class NoLockTimer : IDisposable
{
    private readonly System.Timers.Timer _timer;

    private bool _isTimerStopped = false;
    private readonly object _isTimerStoppedLock = new object();

    public NoLockTimer()
    {
        _timer = new System.Timers.Timer { AutoReset = false, Interval = 1000 };

        _timer.Elapsed += delegate
        {
            try
            {
                while (!IsTimerStopped && some other condition) 
                {
                    // do stuff
                }
            }
            catch (Exception e)
            {
                // Do some logging
            }
            finally
            {
                if (!IsTimerStopped) 
                {
                    _timer.Start(); // <- Manual restart.
                }
            }
        };

        _timer.Start();
    }

    public void Stop()
    {
        IsTimerStopped = true;
        if (_timer != null)
        {
            _timer.Stop();
        }
    }

    private bool IsTimerStopped
    {
        get 
        {
            lock (_isTimerStoppedLock)
            {
                return _isTimerStopped;
            }
        }
        set 
        {
            lock (_isTimerStoppedLock)
            {
                _isTimerStopped = value;
            }
        }
    }

    public void Dispose()
    {
        Stop();
        if (_timer != null)
        {
            _timer.Dispose();
        }
    }
} 

最佳答案

不,这不安全。 Elapsed 事件处理程序在线程池线程上调用。您无法预测该线程何时实际调用您的方法,这取决于进程中正在运行的其他 TP 线程。同时进行两个通话在技术上是可行的。这使得 isElapsedAlreadyRunning 变量上的 volatile 关键字不足以确保该方法是线程安全的,您必须改用 lock 关键字或 Monitor.TryEnter() .

当您将 Timer 的 AutoReset 属性设置为 false 时,这个问题就会消失。确保在 finally block 中重新启动计时器,Timer.Elapsed 事件的另一个令人讨厌的问题是异常在没有诊断的情况下被吞没。 System.Threading.Timer 是一个全面的更好的计时器,这样的意外更少。

Timer.Enabled 属性也有类似的问题,你总会迟到。

关于c# - System.Timers.Timer.Enabled 属性线程安全吗,是否可以从计时器的 Elapsed 事件访问它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14564173/

相关文章:

c# - 将 UpdateDefinition<TEntity> 用于 MongoDB 通用存储库

c# - 从 MHT 文档中提取内容

c# - 在通过 Sharepoint 中的代码创建发布页面之前,如何检查发布页面是否存在?

java - 了解监听器通知程序上的同步

java - 转到另一个 Activity 时 Timer() 函数不起作用

c++ - std::system_clock 和 std::steady_clock 之间的区别?

javascript - Angular.js 的 ASP.NET 捆绑和缩小错误

c - 使用pthread_exit终止并返回的线程终止-奇怪的示例

c - 在 GTK 中使用多线程?

java - Java中的定时器不暂停程序?