我的 AsyncTimer class 实现线程安全吗?

Is my AsyncTimer class implementation thread safe?

我正在编写一个简化的异步事件驱动 Timer class。只是想知道这是否会在所有条件下工作,以及它是否是线程安全的。 IE,在调用或读取 Enabled 属性 或设置 AutoReset 功能期间它有任何失败的可能性。

namespace Sandbox
{
    public class AsyncTimer
    {
        public volatile bool AutoReset = true;
        volatile bool enabled = false;
        public volatile int Interval;

        CancellationTokenSource? cts;

        public volatile Action? Elapsed;

        public bool Enabled { get { return enabled; } }

        public AsyncTimer (int interval) => Interval = interval;

        public void Start(bool startElapsed = false)
        {
            if (startElapsed) Elapsed?.Invoke();
            enabled = true;
            cts = new();
            _ = Task.Run(() => RunTimerAsync());
        } 

        public void Stop()
        {
            enabled = false;
            cts?.Cancel();
        }

        async void RunTimerAsync()
        {
            while (enabled && !cts!.IsCancellationRequested)
            {
                await Task.Delay(Interval);
                Elapsed?.Invoke();
                if (!AutoReset) cts.Cancel();
            }
        }
    }
}

据我所知,这只是 Threading.Timer 的包装,周围有一堆额外的东西,没有添加任何实际功能。你的计时器通过调用 Task.Delay 来工作,但这只是 Threading.Timer 的包装,所以你最好去掉中间人。

您公开的大部分功能已由该计时器通过调用 .Change 方法提供。如果你想提供一个更直观的界面,我建议包装这个计时器,或者提供一些扩展方法。

如果您想要保证不会同时引发事件的行为,并且 execution-time 被添加到周期时间,您应该包装计时器并设置一些 due-time 和一个无限期。然后在事件处理程序结束时,您将再次调用 .Change 以重新启动计时器。

如果您围绕 Threading.Timer 编写一个简单的包装器,您将更容易确保线程安全,因为 Threading.Timer 是线程安全的。

实际上,我认为您的 class 可能是线程安全的。但我相当确定它会导致一些意想不到的行为。例如,多次调用 .Start() 将导致启动多个循环。我本来期望这样的方法是幂等的。