C# &引用;原子地;更改System.Threading.Timer
假设我有一个现有的System.Threading.Timer实例,我想对其调用Change以将其触发时间向后推:C# &引用;原子地;更改System.Threading.Timer,c#,.net,C#,.net,假设我有一个现有的System.Threading.Timer实例,我想对其调用Change以将其触发时间向后推: var timer = new Timer(DelayCallback, null, 10000, Timeout.Infinite); // ... (sometime later but before DelayCallback has executed) timer.Change(20000, Timeout.Infinite); 我使用这个计时器在一段时间没有活动后执行“
var timer = new Timer(DelayCallback, null, 10000, Timeout.Infinite);
// ... (sometime later but before DelayCallback has executed)
timer.Change(20000, Timeout.Infinite);
我使用这个计时器在一段时间没有活动后执行“空闲回调”。(“空闲”和“无活动”在本例中是应用程序定义的条件……具体情况并不十分重要。)每次执行“操作”时,我都要重置计时器,使其始终设置为在10秒后启动
然而,有一个固有的竞争条件,因为当我调用Change时,我无法判断计时器是否已经根据其旧设置触发。(当然,我可以告诉您是否发生了回调,但我无法告诉CLR的内部计时器线程是否已将我的回调排入线程池队列,并且回调即将执行。)
现在我知道我可以调用timer实例上的Dispose,并在每次需要“向后推”时重新创建它。但这似乎不如仅仅改变现有的计时器有效。当然可能不是……我稍后会运行一些微基准测试,让大家都知道
或者,我可以始终跟踪预期的触发时间(通过DateTime.Now.AddSeconds(10)),如果原始计时器触发,则通过在回调中检查DateTime.Now来忽略它。(我一直担心这可能不是100%可靠,因为计时器使用TimeSpan,我的支票使用DateTime…这可能不是问题,但出于某种原因,我对它不太满意…)
我的问题是:
谢谢 实际上,我不得不为自己制作的MMORPG构建自己的“计时”类。它可以跟踪超过100000个“实体”,这些实体拥有处理人工智能和其他任务的计时器。基于可能采取的不同行动,我将不得不暂时推迟事件 现在,我的计时课程完全是手工编写的,所以它不是你想要的。但你可以做一些类似于我提出的解决方案的事情,就是做一种:
while (sleepyTime > 0)
{
int temp = sleepyTime;
sleepyTime = 0;
Thread.Sleep(temp);
}
// here's where your actual code is.
然后,您可以创建一个“延迟”方法,基本上只向SleepTime发送广告。听起来您真正想要的是应用程序空闲事件
System.Windows.Forms.Application.Idle
我将您的问题解释为要求实现下面指定的IdleNotifier接口。您还声明ActionOccursed()需要快速
public delegate void IdleCallback();
public interface IdleNotifier
{
// Called by threadpool when more than IdleTimeSpanBeforeCallback
// has passed since last call on ActionOccured.
IdleCallback Callback { set; }
TimeSpan IdleTimeSpanBeforeCallback { set; }
void ActionOccured();
}
我在下面提供了System.Threading.Timer的实现。
关于实施的要点:
public class IdleNotifierTimerImplementation : IdleNotifier
{
private readonly object SyncRoot = new object();
private readonly Timer m_Timer;
private IdleCallback m_IdleCallback = null;
private TimeSpan m_IdleTimeSpanBeforeEvent = TimeSpan.Zero;
// Null means there has been no action since last idle notification.
private DateTime? m_LastActionTime = null;
public IdleNotifierTimerImplementation()
{
m_Timer = new Timer(OnTimer);
}
private void OnTimer(object unusedState)
{
lock (SyncRoot)
{
if (m_LastActionTime == null)
{
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
return;
}
TimeSpan timeSinceLastUpdate = DateTime.UtcNow - m_LastActionTime.Value;
if (timeSinceLastUpdate > TimeSpan.Zero)
{
// We are no idle yet.
m_Timer.Change(timeSinceLastUpdate, TimeSpan.Zero);
return;
}
m_LastActionTime = null;
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
}
if (m_IdleCallback != null)
{
m_IdleCallback();
}
}
// IdleNotifier implementation below
public void ActionOccured()
{
lock (SyncRoot)
{
m_LastActionTime = DateTime.UtcNow;
}
}
public IdleCallback Callback
{
set
{
lock (SyncRoot)
{
m_IdleCallback = value;
}
}
}
public TimeSpan IdleTimeSpanBeforeCallback
{
set
{
lock (SyncRoot)
{
m_IdleTimeSpanBeforeEvent = value;
// Run OnTimer immediately
m_Timer.Change(TimeSpan.Zero, TimeSpan.Zero);
}
}
}
}
- 我们接受计时器可以在任何时候唤醒,并确保这是正常的
- 因为我们假设计时器很少唤醒,所以我们可以在这些时候做昂贵的工作
- 因为我们可以在计时器回调中执行所有逻辑,所以“推计时器”所需要做的就是记住上次推计时器的时间
public class IdleNotifierTimerImplementation : IdleNotifier
{
private readonly object SyncRoot = new object();
private readonly Timer m_Timer;
private IdleCallback m_IdleCallback = null;
private TimeSpan m_IdleTimeSpanBeforeEvent = TimeSpan.Zero;
// Null means there has been no action since last idle notification.
private DateTime? m_LastActionTime = null;
public IdleNotifierTimerImplementation()
{
m_Timer = new Timer(OnTimer);
}
private void OnTimer(object unusedState)
{
lock (SyncRoot)
{
if (m_LastActionTime == null)
{
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
return;
}
TimeSpan timeSinceLastUpdate = DateTime.UtcNow - m_LastActionTime.Value;
if (timeSinceLastUpdate > TimeSpan.Zero)
{
// We are no idle yet.
m_Timer.Change(timeSinceLastUpdate, TimeSpan.Zero);
return;
}
m_LastActionTime = null;
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
}
if (m_IdleCallback != null)
{
m_IdleCallback();
}
}
// IdleNotifier implementation below
public void ActionOccured()
{
lock (SyncRoot)
{
m_LastActionTime = DateTime.UtcNow;
}
}
public IdleCallback Callback
{
set
{
lock (SyncRoot)
{
m_IdleCallback = value;
}
}
}
public TimeSpan IdleTimeSpanBeforeCallback
{
set
{
lock (SyncRoot)
{
m_IdleTimeSpanBeforeEvent = value;
// Run OnTimer immediately
m_Timer.Change(TimeSpan.Zero, TimeSpan.Zero);
}
}
}
}
这段代码有许多直接的性能改进
如果有人对我的第一个想法感兴趣,就问我