我需要一个具有以下行为的计时器:
我玩CreateTimerQueueTimer
并取得了一些成功,但同时在删除计时器时遇到代码重入和/或锁定问题。
我决定创建自己的计时器,以便我可以更好地了解引擎盖下发生的事情,以便我可以解决锁定和重入问题。我的代码似乎很好用,让我相信我也可以使用它。它看起来好听吗?
我已经检查了是否删除了计时器,以确保在再次创建计时器之前删除已完成。那看起来不错吗?
注意:我应该说我要调用timeBeginPeriod(1)
和timeEndPeriod(1)
以达到毫秒精度。
(以下代码从vb.net转换为c#,所以对任何错过的混乱道歉}
ETA:我发现它有问题。如果计时器以1毫秒的间隔运行,我打电话给Change(300)
,它会锁定@ while(this.DeleteRequest
)。这个
必须是因为TimerLoop
在this.CallbackDelegate.Invoke(null)
电话中。
public class MyTimer : IDisposable
{
private System.Threading.TimerCallback CallbackDelegate;
private bool DeleteRequest;
private System.Threading.Thread MainThread;
public MyTimer(System.Threading.TimerCallback callBack)
{
this.CallbackDelegate = callBack;
}
public void Create(int interval)
{
while (this.DeleteRequest) {
System.Threading.Thread.Sleep(0);
}
if (this.MainThread != null) {
throw new Exception("");
}
this.MainThread = new System.Threading.Thread(TimerLoop);
// Make sure the thread is automatically killed when the app is closed.
this.MainThread.IsBackground = true;
this.MainThread.Start(interval);
}
public void Change(int interval)
{
// A lock required here?
if (!this.IsRunning()) {
throw new Exception("");
}
this.Delete();
this.Create(interval);
}
public void Delete()
{
this.DeleteRequest = true;
}
public bool IsRunning()
{
return (this.MainThread != null) && this.MainThread.IsAlive;
}
private void TimerLoop(object args)
{
int interval = (int)args;
Stopwatch sw = new Stopwatch();
sw.Start();
do {
if (this.DeleteRequest) {
this.MainThread = null;
this.DeleteRequest = false;
return;
}
long t1 = sw.ElapsedMilliseconds;
// I want to wait until the operation completes, so I use Invoke.
this.CallbackDelegate.Invoke(null);
if (this.DeleteRequest) {
this.MainThread = null;
this.DeleteRequest = false;
return;
}
long t2 = sw.ElapsedMilliseconds;
int temp = Convert.ToInt32(Math.Max(interval - (t2 - t1), 0));
sw.Reset();
if (temp > 0) {
System.Threading.Thread.Sleep(temp);
}
sw.Start();
} while (true);
}
// The dispose method calls this.Delete()
}
答案 0 :(得分:1)
我建议使用p / Invoke并使用Win32的计时器队列中的计时器:
http://msdn.microsoft.com/en-us/library/ms686796(v=vs.85).aspx
应该注意托管CLR环境中内置了很多非确定性,例如垃圾收集。仅仅因为你的计时器有一个1毫秒的时间并不意味着必然会发生这种情况。
此外,文档没有提及它,但是计时器调用的回调必须固定在内存中,而不是通过GCHandle
或其他构造进行垃圾收集。当一个计时器(或计时器,如果你杀掉一个计时器队列),回调将最后一次执行。不确定是通过内部等待到期还是通过发信号通知内部事件句柄来发生这种情况。
DeleteTimerQueueTimer()
和DeleteTimerQueueEx()
的执行可以同步,因此在所有计时器都发出信号并调用它们的最后一个回调之前它们不会返回,但这样做是不理想的。
如果你没有固定回调并防止它们被垃圾收集,那么事情就会在很多时候发生。你会遇到随机异常。
此外,如果正在删除计时器,回调应该足够智能以挽救,以免它引用已经GC的东西。
答案 1 :(得分:0)
μTimer是一个更好的例子!
找到它它提供精确的等待时间,最短1μs,可能更低,具体取决于您的NIC!
如果您还有其他需要,请告诉我们!