在我的Windows服务应用程序中,我经常使用定时器。我只使用System.Timers。我以前从未遇到过这个问题,但突然间我得到了这个异常:
在我的方法中,我停止了计时器并改变了计时器的间隔。那就是我遇到异常的地方。
我读到了一些关于这个bug的内容,但即使在.NET 3.5中仍然可能存在这个bug吗?
我该如何修复它?我应该在停止计时器后更新计时器对象并将间隔设置为新对象吗?我正在使用GC.KeepAlive(dataTimer);
编辑: 我发现了一些关于这个问题的其他问题:
*我找到了一个链接http://www.kbalertz.com/kb_842793.aspx 基本上,当你停止计时器时,内部的System.Threading.Timer就会变得可用于垃圾回收,有时会导致经过的事件不发生,或者有时会导致已释放引用异常。 虽然文章中没有描述,但我的解决方案是每次停止计时器并重新添加经过的事件时创建一个新的计时器。虽然不高效,但对我来说很容易,而且在处理器方面也不是问题。 这完全解决了我的问题。 感谢所有回应的人。
但我对为什么这个bug仍然存在感到困惑,我需要确定重新添加计时器是一个好主意...
引起错误的代码:
计时器在更改间隔之前已停止。 计时器是我的类的私有字段:
System.ObjectDisposedException: Cannot access a disposed object.
at System.Threading.TimerBase.ChangeTimer(UInt32 dueTime, UInt32 period)
at System.Threading.Timer.Change(Int32 dueTime, Int32 period)
at System.Timers.Timer.UpdateTimer()
at System.Timers.Timer.set_Interval(Double value)
at MyApp.MySpace.MySpace2.MyClassWithTimer.MethodChangeTimerInterval()
在我的方法中,我停止了计时器并改变了计时器的间隔。那就是我遇到异常的地方。
我读到了一些关于这个bug的内容,但即使在.NET 3.5中仍然可能存在这个bug吗?
我该如何修复它?我应该在停止计时器后更新计时器对象并将间隔设置为新对象吗?我正在使用GC.KeepAlive(dataTimer);
编辑: 我发现了一些关于这个问题的其他问题:
*我找到了一个链接http://www.kbalertz.com/kb_842793.aspx 基本上,当你停止计时器时,内部的System.Threading.Timer就会变得可用于垃圾回收,有时会导致经过的事件不发生,或者有时会导致已释放引用异常。 虽然文章中没有描述,但我的解决方案是每次停止计时器并重新添加经过的事件时创建一个新的计时器。虽然不高效,但对我来说很容易,而且在处理器方面也不是问题。 这完全解决了我的问题。 感谢所有回应的人。
但我对为什么这个bug仍然存在感到困惑,我需要确定重新添加计时器是一个好主意...
引起错误的代码:
private void StartAsyncResponseTimer()
{
switch (_lastRequestType)
{
case 1:
asyncResponseTimer.Interval = 1000;
break;
case 2:
asyncResponseTimer.Interval = 2000;
break;
case 3:
asyncResponseTimer.Interval = 3000;
break;
default:
asyncResponseTimer.Interval = 10000;
break;
}
asyncResponseTimer.Start();
}
从SerialPortDataReceived事件调用了该函数:
private void SerialPortDataReceived(object sender, EventArgs e)
{
StartAsyncResponseTimer();
}
计时器在更改间隔之前已停止。 计时器是我的类的私有字段:
private Timer asyncResponseTimer = new Timer();
编辑:该应用程序已连续运行数月,这是我第一次遇到此异常!
我的处理模式:
public class SerialPortCommunication{
...
private void SerialPortDataReceived(object sender, EventArgs e)
{
ReadResponse();
StartAsyncResponseTimer();
}
//used to determine if is recieving response over
private void StartAsyncResponseTimer()
{
switch (_lastRequestType)
{
case 1:
asyncResponseTimer.Interval = 1000;
break;
case 2:
asyncResponseTimer.Interval = 2000;
break;
case 3:
asyncResponseTimer.Interval = 3000;
break;
default:
asyncResponseTimer.Interval = 10000;
break;
}
asyncResponseTimer.Start();
}
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// Dispose managed resources.
}
// Dispose unmanaged resources.
_disposed = true;
Stop();
}
}
~SomeClass()
{
Dispose(false);
}
#endregion
public void Stop()
{
_asyncResponseTimer.Stop();
serialPortManager.ClosePort();
}
}