Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET 3.5 C# Bug with System.Timer System.ObjectDisposedException: Cannot access a disposed object

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();
    }
}
like image 538
Simon Avatar asked Jan 25 '11 12:01

Simon


People also ask

Is .NET 3.5 still needed?

You may need the . NET Framework 3.5 to run an app on Windows 11, Windows 10, Windows 8.1, and Windows 8. You can also use these instructions for earlier Windows versions.

What is Microsoft .NET Framework 3.5 used for?

NET Framework is used to create and run software applications. . NET apps can run on many operating systems, using different implementations of . NET. . NET Framework is used for running .

Is .NET 3.5 a security risk?

NET Framework 3.5. 1 is vulnerable to remote code execution attacks.


2 Answers

Can it be that your getting serial port data just after you have disposed your timer? It is the only thing that comes to my mind with the data you have posted!. What are you doing in the Stop()! method inside the Dispose()????

like image 108
miguel.hpsgaming Avatar answered Nov 05 '22 12:11

miguel.hpsgaming


It seems as you start your timer when receiving data on the serial port. What happens if you receive additional data on the port before the timer has finished sending the response? It seems, based on the information you have posted, that the timer interval then will be changed and started (again) while timer still is processing its timer event.

Have you considered the above scenario? Is the timer AutoReset or not? When are you calling Stop()?

like image 43
lennartk Avatar answered Nov 05 '22 12:11

lennartk