Question

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?

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top