我是C#的新手,我需要为我用来监控硬件的小应用程序使用计时器。我找到了一些计时器的参考代码,但它使用了DoEvents()。因为,我运行计时器很长一段时间,有时几天和几个小时,我开始得到堆栈溢出。我现在明白DoEvents()正在引起这种情况,这是大多数人推荐使用的东西。您建议我使用什么功能代替DoEvents来设置我的计时器?
我的代码:
private void BeginMonitoringClick() {
{
myTimer.Tick += new EventHandler(TimerEventProcessor); // myTimer declared elsewhere
myTimer.Interval = 2000;
myTimer.Start();
while(!exitFlag)
{
Application.DoEvents();
}
}
private void TimerEventProcessor(Object myObject, EventArgs myEventArgs){
// Talk to hardware, see if it is doing OK
}
答案 0 :(得分:0)
重复按下按钮会导致StackOverflowException
可能。这将导致BeginMonitoringClick()
方法被递归调用,最终会溢出堆栈。
如果没有看到剩下的代码,就无法确定。在使用DoEvents()
一次的代码中,看到它在整个地方使用的情况并不少见。您可能在其他地方遇到类似的错误,每个错误都会导致问题。
就个人而言,我希望Microsoft从未包含DoEvents()
方法,也不包括其兄弟Control.Refresh()
和Control.Update()
。它们的使用可能导致这种基于重入的错误,并且我从未见过实际需要使用它们的情况。总是有一个更合适的解决方案。
正如其他人所说,要修复此代码中的特定错误,您应该只需通过删除循环来更改代码:
private void BeginMonitoringClick() {
{
myTimer.Tick += TimerEventProcessor; // myTimer declared elsewhere
myTimer.Interval = 2000;
myTimer.Start();
}
private void TimerEventProcessor(object myObject, EventArgs e) {
// Talk to hardware, see if it is doing OK
}
您的代码示例中不清楚exitFlag
变量的用途,因此我无法解释替代方案。但是,如果它旨在用于暂停/终止对硬件的监控,那么您实际需要做的就是稍后在需要时调用myTimer.Stop()
。
答案 1 :(得分:-1)
我建议你使用后台线程。
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var backgroundTask = Task.Factory.StartNew( () => {
while(!token.IsCancellationRequested)
{
Thread.Sleep(2000);
// do work here
}
} , token );
// save your tokenSource somewhere then you can cancel the thread whenever you are done with it.
tokenSource.Cancel();