【问题标题】:Unexpected "Cannot access a disposed object" in clean up method清理方法中出现意外的“无法访问已处理的对象”
【发布时间】:2013-02-18 20:32:39
【问题描述】:

当我关闭我的 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); 上抛出“无法访问已处置的对象”。

我将 bool 值切换为 false 以停止循环,然后中止线程并停止 kinect 设备。

我错过了什么?

【问题讨论】:

    标签: c# wpf kinect objectdisposedexception


    【解决方案1】:

    当您将布尔值设置为 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,你的对象被处理异常了。


    Thread.Abort 是个坏主意。

    你永远不知道执行线程在执行之前多远,这会导致各种讨厌的副作用。在此问答中了解更多信息:What's wrong with using Thread.Abort()

    在你的情况下我会做的是替换

    while(isDisplayActive)
    

    类似的东西

    while(colorThingyThreadIsBusy)
    

    当您的 Thread 准备好(=完成处理)时,将 colorThingyThreadBusy 布尔值设置为 false。

    为了优雅地关闭您的应用程序,我将实现 CancellationToken 而不是中止线程。

    【讨论】:

    • 啊!没想到第四步!你是对的。 你永远不知道执行线程在执行前走了多远
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 2011-10-23
    • 2011-03-25
    • 1970-01-01
    相关资源
    最近更新 更多