C#[.NET 3.5]多线程和位图-不同/不一致的错误

C#[.NET 3.5]多线程和位图-不同/不一致的错误,c#,.net,multithreading,image-processing,bitmap,C#,.net,Multithreading,Image Processing,Bitmap,我正在使用.NET3.5上的C#(无法使用更高版本) 我有一个阻塞队列的实现,它松散地基于 我在同一命名空间中有4个文件: 文件0包含主函数,并为func1启动两个线程 和func2,并实例化上述队列的一个对象 File1具有func1,它将视频分割为单独的图像帧(位图),并将其排入上述队列。如果添加了所有项目,则会 表示已完成添加到队列。担任制作人 File2有一个func2,它检查队列中是否有可用的项,然后将第一个元素出列。充当消费者 包含队列的实现 重要的代码位 职能1 无论何时运行,fu

我正在使用.NET3.5上的C#(无法使用更高版本)

我有一个阻塞队列的实现,它松散地基于

我在同一命名空间中有4个文件:

  • 文件0包含主函数,并为func1启动两个线程 和func2,并实例化上述队列的一个对象
  • File1具有func1,它将视频分割为单独的图像帧(位图),并将其排入上述队列。如果添加了所有项目,则会 表示已完成添加到队列。担任制作人
  • File2有一个func2,它检查队列中是否有可用的项,然后将第一个元素出列。充当消费者
  • 包含队列的实现
  • 重要的代码位

    职能1

    无论何时运行,func1都会按预期运行,但func2在尝试访问image.Height时会抛出不同类型的错误。我看到的一些错误是

    (一)

    (二)

    (三)

    猜猜我做错了什么?我不能对位图使用多线程吗

    我觉得问题可能出在func1中的oneFrame.Dispose()中,这只是一种预感:

    尝试将其放置在using语句之外: 与此相反:

            using (Bitmap image = ImageProcessor.frameQueue.Dequeue())
            {
    
                Console.WriteLine("Height: " + image.Height);
                Console.WriteLine("Width: " + image.Width);                    
            }  
    
    试试这个:

                Bitmap image = new Bitmap((System.Drawing.Image)ImageProcessor.frameQueue.Dequeue());             
                    Console.WriteLine("Height: " + image.Height);
                    Console.WriteLine("Width: " + image.Width);                    
                image.Dispose();
    
    编辑

    bool IsComplete = false;
    while (!(IsComplete = ImageProcessor.frameQueue.isCompleted())) 
                {             
                    using (Bitmap image = ImageProcessor.frameQueue.Dequeue())
                    {
                        Console.WriteLine("Height: " + image.Height);
                        Console.WriteLine("Width: " + image.Width);                    
                    }                
                }
    

    尝试删除
    oneFrame.Dispose()来自func1。它在排队后立即被标记为处置。它看起来像是func2正在使用一次性对象,并且当它退出
    使用
    块时,仍将尝试处置它


    编辑:需要记住的一件事是,如果func2无法通过您创建的所有对象,您将有未经散点的对象挂起。在生产者/消费者模型中,消费者有责任处理所生产的内容。

    @user3243571-参见我编辑的代码-基本上是从dequeud帧的图像构造位图。不,这也不起作用。我感觉问题可能出在oneFrame.Dispose()中func1@user3243571我刚刚注意到-您正在使用一个阻塞队列,它可能在while语句中被阻塞,请在每次迭代中重新分配变量:bool IsComplete=false;虽然(!(IsComplete=ImageProcessor.frameQueue.isCompleted())我做了同样的事情,但它仍然有效。然而,当它必须处理大量的帧时,这似乎会在以后的过程中引起问题。本质上,func2()包含的不仅仅是打印高度和宽度,因此处理每个位图需要一段时间,而func1()的速度非常快。您没有任何限制项目上限的内容。您可以考虑在将函数添加到函数(函数)中的队列之后检查队列大小,并强制它等待直到低于最大值。YEP,这正是我在观察到这种行为后决定要做的。谢谢虽然我已经让消费者等待生产商在队列中放置项目。现在我需要让生产者等待消费者从队列中删除项目。我来了!只要保证当func1()发出信号时,在func2()中isCompleted()将返回true,就应该没有问题。如果isCompleted()即使在完成后仍继续返回false,func2()将永远等待。oneFrame.Dispose()完全错误,您必须删除它。如果这是针对Windows的,并且位图具有窗口句柄(因此它们是基于GDI的,具有设备上下文而不仅仅是内存映射),则您不能在WindProc主线程之外使用它们。如果您这样做,将使WinAPI无效(就像主线程之外的任何其他可视组件调用一样),通常一开始不会发生任何错误,但过了一段时间,您会遇到随机访问冲突,并在不相关的WinAPI或GDI调用上崩溃。有时需要几分钟,有时只需要几秒钟…(最后一次测试是在Win XP上进行的,因此新版本的表现可能会有所不同)
    An unhandled exception of type 'System.NullReferenceException' occurred 
    Additional information: Object reference not set to an instance of an object.
    
    An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll
    Additional information: Parameter is not valid.
    
            using (Bitmap image = ImageProcessor.frameQueue.Dequeue())
            {
    
                Console.WriteLine("Height: " + image.Height);
                Console.WriteLine("Width: " + image.Width);                    
            }  
    
                Bitmap image = new Bitmap((System.Drawing.Image)ImageProcessor.frameQueue.Dequeue());             
                    Console.WriteLine("Height: " + image.Height);
                    Console.WriteLine("Width: " + image.Width);                    
                image.Dispose();
    
    bool IsComplete = false;
    while (!(IsComplete = ImageProcessor.frameQueue.isCompleted())) 
                {             
                    using (Bitmap image = ImageProcessor.frameQueue.Dequeue())
                    {
                        Console.WriteLine("Height: " + image.Height);
                        Console.WriteLine("Width: " + image.Width);                    
                    }                
                }