C# 关闭延迟定时器
有没有一种方法可以使用一个System.Threading.timer对象在C#中编写一个安全的1秒延时计时器类 或者,假设输入的打开和关闭速度比每秒一次快得多,那么通常最简单的解决方案是什么 关闭延迟计时器可通过此接口进行描述:C# 关闭延迟定时器,c#,multithreading,timer,race-condition,C#,Multithreading,Timer,Race Condition,有没有一种方法可以使用一个System.Threading.timer对象在C#中编写一个安全的1秒延时计时器类 或者,假设输入的打开和关闭速度比每秒一次快得多,那么通常最简单的解决方案是什么 关闭延迟计时器可通过此接口进行描述: public interface IOffDelay { /// <summary> /// May be set to any value from any thread. /// </summary> boo
public interface IOffDelay
{
/// <summary>
/// May be set to any value from any thread.
/// </summary>
bool Input { get; set; }
/// <summary>
/// Whenever Input is true, Output is also true.
/// The Output is only false at startup
/// or after the Input has been continuously off for at least 1 second.
/// </summary>
bool Output { get; }
}
我可以看出此解决方案中存在竞争条件:
public sealed class OffDelay : IOffDelay, IDisposable
{
public OffDelay()
{
timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
}
public void Dispose()
{
timer.Dispose();
}
public bool Input
{
get
{
lock (locker)
return _input;
}
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
if (_input == true)
_output = true;
else
{
stopwatch.Restart();
if (!timerRunning)
timer.Change(1000, Timeout.Infinite);
}
}
}
}
private bool _input;
public bool Output
{
get
{
lock (locker)
return _output;
}
}
private bool _output;
private readonly object locker = new object();
private readonly Timer timer;
private readonly Stopwatch stopwatch = new Stopwatch();
private bool timerRunning;
private void TimerCallback(object state)
{
lock (locker)
{
if (_input == true)
timerRunning = false;
else
{
var remainingTimeMs = 1000 - stopwatch.ElapsedMilliseconds;
if (remainingTimeMs > 0)
timer.Change(remainingTimeMs, Timeout.Infinite);
else
{
_output = false;
timerRunning = false;
DoSomething();
}
}
}
}
private void DoSomething()
{
// ...
}
}
如果没有一个好的答案来清楚地说明这个问题,包括确切地说明上下文是什么以及可能存在哪些约束,那么就不可能确切地知道什么答案适合你
但根据您在问题中包含的内容,我将更改您的实现,使其不依赖计时器:
public sealed class OffDelay : IOffDelay
{
public bool Input
{
get { lock (locker) return _input; }
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
_lastInput = DateTime.UtcNow;
}
}
}
private bool _input;
public bool Output
{
get { lock (locker) return (DateTime.UtcNOw - _lastInput).TotalSeconds < 1; }
}
private DateTime _lastInput;
}
公开密封的延迟等级:IOffDelay
{
公共布尔输入
{
获取{lock(locker)return}
设置
{
锁(储物柜)
{
如果(值==\u输入)
返回;
_输入=值;
_lastInput=DateTime.UtcNow;
}
}
}
私人布尔输入;
公共布尔输出
{
获取{lock(locker)return(DateTime.UtcNOw-_lastInput).TotalSeconds<1;}
}
私有日期时间\u lastInput;
}
请注意,上述内容容易受到计算机时钟变化的影响。如果需要独立于时钟工作,可以将
DateTime.UtcNow
替换为Stopwatch
实例,每次更改Input
属性时调用Reset()
,并使用秒表的appead
属性来确定自上次输入以来的时间长度。我试图避免在发布的问题中出现不必要的复杂情况,但我想我无意中遗漏了一个关键部分:当输出变为false时,类需要做一些事情。不过,你的答案对于所问的问题是正确的,它为我提供了真正解决问题所需的提示。
public sealed class OffDelay : IOffDelay
{
public bool Input
{
get { lock (locker) return _input; }
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
_lastInput = DateTime.UtcNow;
}
}
}
private bool _input;
public bool Output
{
get { lock (locker) return (DateTime.UtcNOw - _lastInput).TotalSeconds < 1; }
}
private DateTime _lastInput;
}