.NET 3.5的C#错误与System.Timer System.ObjectDisposedException:无法访问已释放的对象 [英] .NET 3.5 C# Bug with System.Timer System.ObjectDisposedException: Cannot access a disposed object

查看:3694
本文介绍了.NET 3.5的C#错误与System.Timer System.ObjectDisposedException:无法访问已释放的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Windows服务应用程序,我使用的计时器很多。我只用System.Timers。 我以前从来没有遇到过这个问题,但我突然得到这个异​​常:

  System.ObjectDisposedException:无法访问已释放的对象。
   在System.Threading.TimerBase.ChangeTimer(UInt32的duetime参数,UInt32的时期)
   在System.Threading.Timer.Change(的Int32 duetime参数,的Int32期)
   在System.Timers.Timer.UpdateTimer()
   在System.Timers.Timer.set_Interval(Double值)
   在MyApp.MySpace.MySpace2.MyClassWithTimer.MethodChangeTimerInterval()
 

在我的方法,我停止定时器和改变定时器的时间间隔。这就是我得到异常的地方。

我看过一些有关这个错误,但它仍然允许通过有这个漏洞,即使在.NET 3.5?

如何解决呢?我应该更新计时器对象停药后,并设置间隔为一个新的对象?我使用GC.KeepAlive(dataTimer);

编辑: 我发现这个问题的一些其他问题:

*我发现一个链接 http://www.kbalertz.com/kb_842793.aspx 基本上只要你停止计时,内部 System.Threading.Timer变为可用于垃圾收集, 有时会造成经过事件不发生,或有时 造成处置引用异常。 虽然在本文未描述的,我的解决办法是 每次计时器是成为以创建一个新的计时器 停止并重新添加所经过的事件。效率不高,但方便, 而不是一个问题,处理器的聪明给我。 这已经完全解决了我的问题。 干杯所有谁回答。*

不过,我很困惑,为什么这个错误仍然存​​在,我需要确保重新添加定时器是个好主意......

这导致错误code:

 私人无效StartAsyncResponseTimer()
{
    开关(_lastRequestType)
    {
        情况1:
            asyncResponseTimer.Interval = 1000;
            打破;
        案例2:
            asyncResponseTimer.Interval = 2000;
            打破;
        案例3:
            asyncResponseTimer.Interval = 3000;
            打破;
        默认:
            asyncResponseTimer.Interval = 10000;
            打破;
    }

    asyncResponseTimer.Start();
}
 

功能从SerialPortDataReceived事件被称为:

 私人无效SerialPortDataReceived(对象发件人,EventArgs的)
{
       StartAsyncResponseTimer();
}
 

定时器在呼唤着变化区间之前停止。

定时器是我的类的私有字段:

 专用计时器asyncResponseTimer =新的Timer();
 

编辑:应用程序已经运行了数月的连续,这是我第一次得到这个异​​常

我的Dispose模式:

 公共类SerialPortCommunication {

 ...

    私人无效SerialPortDataReceived(对象发件人,EventArgs的)
    {
        ReadResponse();

        StartAsyncResponseTimer();
    }

    //用于确定是否是recieving响应过
    私人无效StartAsyncResponseTimer()
    {
        开关(_lastRequestType)
        {
            情况1:
                asyncResponseTimer.Interval = 1000;
                打破;
            案例2:
                asyncResponseTimer.Interval = 2000;
                打破;
            案例3:
                asyncResponseTimer.Interval = 3000;
                打破;
            默认:
                asyncResponseTimer.Interval = 10000;
                打破;
        }

        asyncResponseTimer.Start();
    }

    公共虚拟无效的Dispose()
    {

        处置(真);
        GC.Sup pressFinalize(本);
    }

    私人无效的Dispose(BOOL处置)
    {
        如果(!this._disposed)
        {
            如果(处置)
            {
                //处置管理的资源。

            }

            //处置非托管资源。
            _disposed = TRUE;

            停止();

        }
    }

    〜SomeClass的()
    {

        处置(假);
    }

    #endregion




    公共无效停止()
    {
        _asyncResponseTimer.Stop();
        serialPortManager.ClosePort();
    }
}
 

解决方案

既然你没有指定服务器配置,我假设在Windows Server 2003。当你提到它的工作(几乎)两个月了,这让我想起了< A HREF =htt​​p://support.microsoft.com/?scid=kb;en-us;944762&x=18&y=13相对=nofollow>49.7天错误。它可能并不适用于你的情况下,除非再次崩溃三月。 : - )

  

症状2
  您多次在应用程序中调用CreateTimerQueueTimer功能:在不运行ISA服务器的Windows Server 2003的计算机上,当满足下列条件为真会发生类似的问题。设置在指定的时间来触发由该CreateTimerQueueTimer函数创建的计时器。

     

应用程序运行超过49.7天。 49.7天后,计时器立即触发,而不是指定的时间后触发。几分钟后,将定时器被正确触发。

的KeepAlive()是不是在这里很有用,因为你声明的计时器在一流水平 - 这是很好的。这是没有必要停止的定时器的间隔的变化。

从调用堆栈和您所提供的code,它看起来像你试图更改布置完毕的定时器的时间间隔。你可能需要确认没有更多的工作要做,而不是这似乎干扰了正在进行的工作,你的Dispose模式停止它,之后停止计时器。也就是说,首先检查是否有再要做的工作,如果没有,停止监听的端口,然后停止计时器。它是不会有很大帮助,除非我能看到的code一些地区 - 如事件处理程序,serialPortManager报关等。

In my Windows service app I am using timers a lot. I'm using only System.Timers. I've never experienced this problem before, but suddenly I got this exception:

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()

In my method I am stopping the timer, and changing the timer interval. That is the place where I got the exception.

I have read something about this bug but is it still passible to have this bug even in .NET 3.5?

How do I fix it? Should I renew the timer object after stopping and set the interval to a new object? I am using GC.KeepAlive(dataTimer);

Edit: I found some other questions about this problem:

*I found a link http://www.kbalertz.com/kb_842793.aspx Basically as soon as you stop a timer, the internal System.Threading.Timer becomes available for Garbage Collection, sometimes causing the elapsed event not to occur, or sometimes causing a disposed reference exception. Although not described in the article, my solution was to create a new timer every time the timer was to be stopped and re-add the elapsed events. Not efficient but easy, and not a problem processor-wise to me. This has totally solved my problem. Cheers for all who responded.*

But I am confused as to why the bug is still there, and I need to be sure that re-adding the timer is a good idea...

Code that caused the error:

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();
}

Function was called from SerialPortDataReceived event:

private void SerialPortDataReceived(object sender, EventArgs e)
{
       StartAsyncResponseTimer();
}

Timer was stopped before calling changing interval.

Timer is private field of my class:

  private Timer asyncResponseTimer = new Timer();

EDIT: The application has been running for several months in a row and this is first time I got this exception!

My dispose pattern:

 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();
    }
}

解决方案

Since you have not specified your server configuration, I am assuming Windows Server 2003. When you mention it worked for (almost) two months, it reminds of the 49.7 days bug. It may not be applicable to your scenario, unless it crashes again in March. :-)

Symptom 2
On a Windows Server 2003-based computer that is not running ISA Server, a similar problem occurs when the following conditions are true: You call the CreateTimerQueueTimer function repeatedly in an application. You set a specified period to trigger the timer that is created by the CreateTimerQueueTimer function.

The application runs for more than 49.7 days. After 49.7 days, the timer is triggered immediately instead of being triggered after the specified period. After several minutes, the timer is triggered correctly.

KeepAlive() is not useful here because you declared the timer at the class level - which is good. It is not necessary to stop the timer for changing the interval.

From the call stack and the code you have provided, it looks like you are trying to change the interval on the already disposed timer. You probably need to stop the timer after confirming there is no more work to do, instead of stopping it in your dispose pattern which seems to interfere with ongoing work. That is, first you check if there is anymore work to be done, if not, stop listening to the port and then stop the timer. It is not going to be of much help unless I can see some more parts of the code - like the event handlers, serialPortManager declaration etc.

这篇关于.NET 3.5的C#错误与System.Timer System.ObjectDisposedException:无法访问已释放的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆