c# - 使用 Aforge.NET 和 Windows 窗体时的线程安全

标签 c# winforms thread-safety .net-4.5 aforge

<分区>

我在让 AForge.NET 与我的 Windows 窗体应用程序一起运行时遇到了很多麻烦。该应用程序需要一个位图流来在自定义 PictureBox 中显示视频,同时使用相同的流来跟踪使用颜色的对象。

我尝试锁定 NewFrame 事件,将图像从视频源复制到临时图像,如下所示,使用监视器。

//Event for when a frame from the video is ready
videoSource.NewFrame += (s, e) =>
{
    if (System.Threading.Monitor.TryEnter(updaterLock, 20))
    {
        Bitmap old = currentImage;

        currentImage = (Bitmap)e.Frame.Clone();
        currentImage.RotateFlip(RotateFlipType.RotateNoneFlipY);

        if (currentImage != null)
        {
            if (ImageUpdated != null)
                ImageUpdated(this, EventArgs.Empty);

            if (old != null)
            {
                old.Dispose();
                old = null;
            }
        }
        else
            currentImage = old;

        System.Threading.Monitor.Exit(updaterLock);
    }
};

上面的代码是返回单例实例的类的一部分,该实例通过属性访问 currentImage。可以找到完整的类 here . 在自定义控件中,像这样访问位图(DisplayControl 类持有对 RgbStream 实例的引用 - 位图流):

Control.DisplayControl.Instance.ImageUpdated += (s, e) => this.Image = Control.DisplayControl.Instance.Bitmap;

访问控件(this.Image)的Image属性时抛出异常(InvalidOperationException),如下所示:

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Cross-thread operation not valid: Control 'gridControl' accessed from a thread other than the thread it was created on.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.get_Handle()
       at System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Control.SetBounds(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Control.set_Size(Size value)
       at SystemInterface.GUI.Controls.OccupancyGridControl.set_Image(Image value) in c:\Users\Stefan\SW505\root\ProductCode\GUI\Controls\OccupancyGridControl.cs:line 64
       at SystemInterface.GUI.Controls.OccupancyGridControl.<.ctor>b__0(Object s, EventArgs e) in c:\Users\Stefan\SW505\root\ProductCode\GUI\Controls\OccupancyGridControl.cs:line 207
       at Control.DisplayControl.<.ctor>b__0(Object s, EventArgs e) in c:\Users\Stefan\SW505\root\ProductCode\Control\DisplayControl.cs:line 36
       at System.EventHandler.Invoke(Object sender, EventArgs e)
       at Services.CameraServices.RgbStream.<.ctor>b__0(Object s, NewFrameEventArgs e) in c:\Users\Stefan\SW505\root\ProductCode\Services\CameraServices\RgbStream.cs:line 121
       at AForge.Video.DirectShow.VideoCaptureDevice.OnNewFrame(Bitmap image)
       at AForge.Video.DirectShow.VideoCaptureDevice.Grabber.BufferCB(Double sampleTime, IntPtr buffer, Int32 bufferLen)
  InnerException: 

关于如何解决这个问题有什么想法吗?谢谢:)

最佳答案

我怀疑您的 GUI 订阅了 ImageUpdated 事件。将您的 RgbStream 方法更改为以下内容:

private RgbStream(VideoCaptureDevice video)
{
    videoSource = video;
    currentImage = null;
    updaterLock = new object();

    if (videoSource == null)
        return;

    //Start the sensor and wait for it to be ready
    videoSource.Start();
    while (!videoSource.IsRunning) { }

    //Event for when a frame from the video is ready
    videoSource.NewFrame += (s, e) =>
    {
        if (System.Threading.Monitor.TryEnter(updaterLock, 20))
        {
            Bitmap old = currentImage;

            currentImage = (Bitmap)e.Frame.Clone();
            currentImage.RotateFlip(RotateFlipType.RotateNoneFlipY);

            if (currentImage != null)
            {
                if (ImageUpdated != null)
                {
                    SynchronizationContext context = SynchronizationContext.Current ?? new SynchronizationContext();
                    context.Send(s =>
                    {
                        ImageUpdated(this, EventArgs.Empty);

                    }, null);
                }

                if (old != null)
                {
                    old.Dispose();
                    old = null;
                }
            }
            else
                currentImage = old;

            System.Threading.Monitor.Exit(updaterLock);
        }
    };
}

关于c# - 使用 Aforge.NET 和 Windows 窗体时的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21572860/

相关文章:

java - 并发:使用非同步方法更改变量

c# - 类继承和构造函数

c# - 如何创建带圆角的用户控件?

面向.NET Core 3.1的C++/CLI

c# - 如何在悬停时更改列表框项目的背景颜色?

c++ - 在单个链表线程中删除和插入是否安全?

c++ - 在某些东西本身变得线程安全之前,你要走多远?

c# - 在 WPF 中重新调整按钮用途的最佳实践?

C# CNTK Sparse(和其他)使用 MinibatchSource

C#:如何使用反射从通用对象中删除所有空属性?