【发布时间】:2011-11-13 04:49:21
【问题描述】:
我需要一个具有以下行为的计时器:
- 毫秒精度
- 我希望仅在当前刻度处理程序完成后才调用刻度事件处理程序(很像 winforms 计时器)
- 我希望主 UI 线程上的异常不会被线程计时器吞没,因此这需要 Invoke/Send 而不是 BeginInvoke/Post
我玩过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()
}
【问题讨论】:
-
你可以尝试在Code Review发帖
-
谢谢,我没听说过那个网站。
-
“毫秒精度”是什么意思?调用 Sleep 将确保您的线程至少在指定的时间内不会再次被调度,但不能保证它何时会被调度。
-
我的意思是,如果我指定 7 毫秒的间隔,那么这就是我将收到的给定或花费一毫秒的时间。诸如 system.threading.timer 之类的计时器不提供这种精度级别。此外,调用 timeBeginPeriod(1) 似乎确实提供了准确的睡眠。
-
你知道
timeBeginPeriod有系统范围的副作用并增加功耗(但我不知道多少)?