【问题标题】:C# Thread for write file to harddisk with ThreadPool使用 ThreadPool 将文件写入硬盘的 C# 线程
【发布时间】:2023-03-13 18:18:02
【问题描述】:

我使用 kinect v2 流来显示彩色图像和身体图像。 现在我想保存彩色图像,但是如果我在主线程中添加代码,我什么也不会显示,因为每秒在硬盘上写入 30 个文件。 所以我考虑使用 Thread,特别是 ThreadPool,但我对 frame 有异常:

ColorCameraSettings 'colorFrame.ColorCameraSettings' ha generato un'eccezione di tipo 'System.ObjectDisposedException'  Microsoft.Kinect.ColorCameraSettings {System.ObjectDisposedException}

这是我的代码:

private void Reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
    {
        var reference = e.FrameReference.AcquireFrame();
        this.StatusText = "NO BODY";

        frameCount++;
        //Console.WriteLine(frameCount);
        bool dataReceived = false;
        //sw.WriteLine("frame nuovo");
        using (ColorFrame frame = reference.ColorFrameReference.AcquireFrame())
        {
            if (frame != null)
            {

                //image.Source = ToBitmap(frame);
                ThreadPool.QueueUserWorkItem(writeColorImage, frame);


            }
        }..............

然后写:

 private void writeColorImage(Object frame)
    {
        ColorFrame colorFrame = (ColorFrame)frame;
        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(ToBitmap(colorFrame)));
        using (var filestream = new FileStream(filelocation + "image" + frameCount + ".jpg", FileMode.Create))
            encoder.Save(filestream);
    }
    private BitmapSource ToBitmap(ColorFrame frame)
    {
        int width = frame.FrameDescription.Width;
        int height = frame.FrameDescription.Height;
        PixelFormat format = PixelFormats.Bgr32;

        byte[] pixels = new byte[width * height * ((PixelFormats.Bgr32.BitsPerPixel + 7) / 8)];

        if (frame.RawColorImageFormat == ColorImageFormat.Bgra)
        {
            frame.CopyRawFrameDataToArray(pixels);
        }
        else
        {
            frame.CopyConvertedFrameDataToArray(pixels, ColorImageFormat.Bgra);
        }

        int stride = width * format.BitsPerPixel / 8;

        return BitmapSource.Create(width, height, 96, 96, format, null, pixels, stride);
    }

如何将这张图片写入硬盘?谢谢

【问题讨论】:

    标签: c# multithreading threadpool kinect filestream


    【解决方案1】:

    using 语句在你的 frame 变量上调用 Dispose;但是,运行保存到磁盘的线程仍在使用对它的引用。这就是为什么你得到例外。更改此代码:

        using (ColorFrame frame = reference.ColorFrameReference.AcquireFrame())
        {
            if (frame != null)
            {
                //image.Source = ToBitmap(frame);
                ThreadPool.QueueUserWorkItem(writeColorImage, frame);
            }
        }
    

    到这里:

        var frame = reference.ColorFrameReference.AcquireFrame();
        if (frame != null)
        {
            //image.Source = ToBitmap(frame);
            ThreadPool.QueueUserWorkItem(writeColorImage, frame);
        }
    

    然后在 writeColorImage 的帧上调用 Dispose();像这样改变方法:

        private void writeColorImage(Object frame)
        {
            var colorFrame = (ColorFrame) frame;
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(ToBitmap(colorFrame)));
            using (var filestream = new FileStream(filelocation + "image" + frameCount + ".jpg", FileMode.Create))
            {
                encoder.Save(filestream);
            }
            colorFrame.Dispose();
        }
    

    【讨论】:

    • frame.Dispose发生错误,Object没有这个方法
    • @luca 抱歉,应该是 colorFrame,我编辑了。
    • 变量framecolorFrame 是对同一个对象的引用。当对对象的任何引用调用Dispose 时,对象将被释放(对于对同一对象的所有引用)。因此,如果对象是通过colorFrame 处置的,则无需处置frame
    【解决方案2】:

    在线程池上开始工作后,您正在处理框架。您应该在作业结束时将其丢弃。

    删除事件处理程序中的 using Reader_MultiSourceFrameArrived,然后:

     private void writeColorImage(Object frame)
        {
            using (ColorFrame colorFrame = (ColorFrame)frame)
            {
                var encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(ToBitmap(colorFrame)));
                using (var filestream = new FileStream(filelocation + "image" + frameCount + ".jpg", FileMode.Create))
                    encoder.Save(filestream);
            }
        }
    

    【讨论】:

    • 如果您针对在 using 语句之外创建的对象使用 using 语句,是否有任何指导方针?我以前从未见过它像这样使用过,总是在通过离开 using 语句的范围而在 using 语句中创建要处置的对象时使用。老实说,我不知道可以像您在示例代码中那样做,但我不确定我是否喜欢它! :)
    • 我的测试表明,C# 在处理传递到using 块的外部创建对象时似乎没有问题。 MSDN 指出,“您可以实例化资源对象,然后将变量传递给 using 语句,但这不是最佳实践。在这种情况下,对象在控制离开 using 块后仍保留在范围内,即使它可能不再存在可以访问其非托管资源。”在这种情况下,我认为,由于替代方案根本没有“使用”块,这可能是规则的例外。也许有一个“使用”总比没有好。
    • 尽快使用为好。在这里你不能这样做(你可以使用 async 但最终结果是一样的)。这很好,因为您的任务将启动(Acquire 和 QueueUserWorkItem 之间没有代码)并且任务的第一行是 using。即使之前出现问题,GC/Finalizer 也会处理它。如果您不喜欢使用关键字,可以添加尝试...最后使用显式 Dispose
    • 以及如何以及何时处理原始框架?
    • @luca 调用 IDisposable.Dispose 或使用 using 关键字并且当您不再使用它时。欲了解更多信息:msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 2013-12-29
    • 2014-12-21
    • 2013-07-05
    • 2011-07-16
    • 1970-01-01
    相关资源
    最近更新 更多