问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/14944808/unexpected-cannot-access-a-disposed-object-in-clean-up-method