清理方法中出现意外的“无法访问已处置的对象”
当我关闭我的WPF应用程序时,我正面临一个令人费解的处理对象问题。 如果你发现我的逻辑中有任何错误,请指出它们。
我有一个带有update()
方法的ColorManager
类,如下所示。
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); }
我在一个单独的线程中运行此方法。 在我的MainWindow.xaml.cs
我有以下内容:
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))); } } }
我在MainWindow.xaml.cs
有以下方法在单击关闭按钮后进行清理。
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"); }
我的应用程序在frame.CopyPixelDataTo(pixelData);
上抛出“无法访问已处置的对象” frame.CopyPixelDataTo(pixelData);
点击关闭按钮后。
我将bool值切换为false以停止循环,然后我中止线程,并停止kinect设备。
我错过了什么?
当您将布尔值设置为false时,应用程序将退出while循环:
1)将你的bool
设置为false
isDisplayActive = false;
2)将退出此循环:
while(isDisplayActive) { using (var frame = kinectSensor.ColorStream.OpenNextFrame(500)) { if (frame == null) continue; if (displayDepthStream) continue; Dispatcher.Invoke(new Action(() => colorManager.Update(frame))); } }
3)所以你的框架也会超出范围。 因此它将被处置……
using (var frame = kinectSensor.ColorStream.OpenNextFrame(500))
4)虽然你的主线程还没有执行Thread.Abort
。
5)因此,您的CopyPixelDataTo
将在已经处置的frame
对象上执行。
frame.CopyPixelDataTo(pixelData);
6)和kaboom,你的对象处理exception。
Thread.Abort是个坏主意。
你永远不知道执行线程在执行之前有多远 ,这可能导致各种令人讨厌的副作用。 在此问答中阅读更多内容: 使用Thread.Abort()有什么问题
在你的情况下我会做的是替换
while(isDisplayActive)
有类似的东西
while(colorThingyThreadIsBusy)
当Thread
准备好(=完成处理)时,将colorThingyThreadBusy
bool设置为false。
为了优雅地关闭你的应用程序,我实现了CancellationToken而不是中止线程。