Search code examples
c#wpfkinectobjectdisposedexception

Unexpected "Cannot access a disposed object" in clean up method


I am facing a puzzling disposed object issue when I shut down my WPF application. If you spot any mistakes in my logic please point them out.

I have a ColorManager class with update() method, as shown below.

public void Update(ColorImageFrame frame)
{
    byte[] pixelData = new byte[frame.PixelDataLength];

    frame.CopyPixelDataTo(pixelData);

    if (Bitmap == null)
    {
        Bitmap = new WriteableBitmap(frame.Width,
                                     frame.Height,
                                     96,
                                     96,
                                     PixelFormats.Bgr32,
                                     null);
    }
    // draw bitmap

    RaisePropertyChanged(() => Bitmap);   
}

I run this method in a separate thread. In my MainWindow.xaml.cs I have the following:

    private void Initialise()
    {
        if (kinectSensor == null)
            return;
        // start kinect sensor        
        kinectSensor.Start();

        updateColourStreamThread = new Thread(new ThreadStart(colorStreamDisplay));
        updateColourStreamThread.Name = "updateColourStreamThread";
        updateColourStreamThread.Start();

        // ...some more codes
     }

        void colorStreamDisplay()
        {
            while(isDisplayActive)
            {
                using (var frame = kinectSensor.ColorStream.OpenNextFrame(500))
                {
                    if (frame == null) continue;

                    if (displayDepthStream) continue;

                    Dispatcher.Invoke(new Action(() => colorManager.Update(frame)));
                }
            }
        }

I have the following method in MainWindow.xaml.cs to do the clean up after clicking the close button.

    private void Clean()
    {
        isDisplayActive = false;
        // some other codes

        if (kinectSensor != null)
        {
            updateColourStreamThread.Abort();
            updateDepthStreamThread.Abort();
            updateSkeletonStreamThread.Abort();

            kinectSensor.Stop();
            kinectSensor = null;
            Console.WriteLine("Closed successfully");
        }

My application throws "cannot access a disposed object" on frame.CopyPixelDataTo(pixelData); after I click the close button.

I switch the bool value to false to stop the loop, then I abort the thread, and stop the kinect device.

What did I miss?


Solution

  • When you set your boolean to false, the application will exit the while loop:

    1) Setting your bool to false

            isDisplayActive = false;
    

    2) will exit this loop:

            while(isDisplayActive)
            {
                using (var frame = kinectSensor.ColorStream.OpenNextFrame(500))
                {
                    if (frame == null) continue;
                    if (displayDepthStream) continue;
    
                    Dispatcher.Invoke(new Action(() => colorManager.Update(frame)));
                }
            }
    

    3) So your frame will go out of scope too. Consequently it will be disposed...

    using (var frame = kinectSensor.ColorStream.OpenNextFrame(500))
    

    4) While your main thread did not yet execute the Thread.Abort yet.

    5) And thus, your CopyPixelDataTo will be executed on an already disposed frame object.

    frame.CopyPixelDataTo(pixelData);
    

    6) And kaboom, you have your object disposed exception.


    Thread.Abort is a bad idea.

    You never know how far the executing thread was before it got executed, which can lead to all kinds of nasty side effects. Read more in this Q&A: What's wrong with using Thread.Abort()

    What I would do in your situation is replace the

    while(isDisplayActive)
    

    with something like

    while(colorThingyThreadIsBusy)
    

    And set the colorThingyThreadBusy bool to false when your Thread is ready (=done processing).

    In order to gracefully close your application I'd implement a CancellationToken instead of aborting Threads.