我的 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()
将导致启动多个循环。我本来期望这样的方法是幂等的。
我正在编写一个简化的异步事件驱动 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()
将导致启动多个循环。我本来期望这样的方法是幂等的。