2013-09-23 61 views
3

我的System.Threading.Timer(它有一个回调)永远不会可靠地触发。这是我的编程任务的一部分,我输入计时器应该从文本框运行的时间量。System.Threading.Timer回调永远不会被调用

定时器声明如下:

System.Threading.Timer timer = new System.Threading.Timer(WorkerObject.callback, null, delay, Timeout.Infinite); 

和延迟是一个简单的描述int为回调火在第一时间延迟(它应该只是一个触发一次)。

回调方法是这样的:

public static void callback(Object stateinfo) 
{ 
    stop = true; 
} 

而且,它设置一个标志,真该停止的循环(正在由一个线程池线程上运行,实际上所有,停止线)。

循环是这样的:

while (!stop) 
{ 
    currentTextbox.Invoke(new Action(delegate() 
    { 
     currentTextbox.AppendText((counter++) + Environment.NewLine); 
     currentTextbox.Update(); 
    })); 
} 

我的问题是,stop变量始终是超过5000毫秒的任何延迟假的。有没有办法“强制”回调始终开火?

+0

这个问题可能不适用(我忘记了API)...但是你启动计时器吗? – Jaxidian

+0

该程序只是打印出一个计数器,它不断递增,直到计时器停止。 System.Threading.Timer不需要启动;它延迟后自动启动(0为无延迟,但在我的情况下,我指定了延迟) – docaholic

+0

@Jaxidian:'System.Threading.Timer'在您创建时启动。 –

回答

9

您需要保持对定时器的引用。

最有可能的是定时器对象被垃圾收集,它将运行它的终结器,停止定时器。

只要您需要计时器存活,请坚持参考。

+0

+1。这是一个阴险的问题。如果您在调试器中运行代码(在调试或发布模式下),则不会收集定时器。但是如果你在没有附加调试器的情况下运行它,定时器将被收集。让我疯狂*第一次遇到那个。 –

+1

@JimMischel:我完全同意。我难忘的时刻是将委托传递给非托管API。调试器连接一切正常,但没有调试器GC得到了更多的积极性。我想我们都有我们的故事:) –

+0

是的,这就是它! @JimMischel,我有同样的问题,在调试器中,计时器会正常工作,但否则计时器会被垃圾收集。 – docaholic

1

运行时抖动可能将您的while(!stop)条件优化为while(true)。 将stop变量标记为volatile。

private volatile bool stop = false; 
+0

可能会工作,但当有其他选项时,我不会建议'volatile'。 –

4

我会建议使用CancellationTokenSource

static CancellationTokenSource Cancel = new CancellationTokenSource(); 

public static void Callback(object state) 
{ 
    Cancel.Cancel(); 
} 

和你的循环:

while (!Cancel.IsCancellationRequested) 
{ 
    ... 
} 

这比使用volatile干净得多,而且更容易,当你移动你的简单的端口概念证明分开类。查看我的博客Polling for Cancellation,了解更多信息。

相关问题