麻烦锁螺纹之间的图像(Trouble with locking an image between t

2019-07-19 00:15发布

我需要获得在两个不同的线程的锁,以便访问一个位图(这是从一个摄像头填充)在EmguCv。 我有一个查询的相机并把它返回到.NET位图“的getFrame”功能。 我有两个线程需要访问该位图,一个需要写入的位图和分配的位图图片框,以及其他需要读取位图,将其转换为一个Image对象并将其赋值给一个EMGU ImageBox。 我首先锁定在任意对象,然后我做我的作业。 的代码如下(_Camera.LiveFrame是位图):

读/写主题:

while (_CaptureThreadRunning)
{
   lock (_Camera)
   { 
      // _Camera.GetFrame writes to the Bitmap
      if (_VideoPlaying && _Camera.GetFrame(500)) 
           pbLiveFeed.Invalidate();
    }
}
_Camera.CloseCamera(true);
_CaptureExitEvent.Set();           // Set to signal captureThread has finished

读/ ImageBox主题:

while (_ProcessThreadRunning)
{
   lock (_Camera)
   {
      //  _Camera.LiveFrame is the Bitmap
      procImage = new Image<Bgr, int>((Bitmap)_Camera.LiveFrame.Clone());          
      procImage.Draw(new Rectangle(10,20,20,15),new Bgr(Color.LightGreen), 5);

      ibProcessed.Image = procImage;
      ibProcessed.Invalidate();
    }
}
_ProcessExitEvent.Set();

这运行正常的大部分时间,但每一个现在,然后我得到一个“对象是在其他地方使用”的错误,当我尝试的clone()位图。 这难道不是锁定的正确方法? 我不明白为什么这会导致问题。

PS。 我的线程可以不再退出优雅无论是。 我.SET()调用之外的我的圈永远不会被调用。 我猜的线程死锁?

Answer 1:

GDI +有一个锁定机制防止两个线程使用Bitmap对象 - 这是您收到的错误。

您试图访问该位图,而UI线程已经访问它。 例如,1)你的位图分配给图片框,2)图片框无效信号,然后重新绘制,3)退出写/读螺纹锁,然后4)读/ imagebox线程试图访问相同的位图而重绘仍在发生。

为了解决这个问题,只是使位图的副本,并使用该副本来操作。 无论你给的图片框,不要以为你可以从一个非UI线程再次触及这一点。

例如,在_Camera.GetFrame:

// Get the bitmap from the camera
capturedBitmap = GetFromCamera();

// Clone the bitmap first before assigning to the picture box
_Camera.LiveFrame = new Bitmap(capturedBitmap);

// Assign to the picture box
pbLiveFeed.Image = capturedBitmap;

现在,_Camera.LiveFrame应该从线程访问,只要你有适当的锁定。

一对夫妇的我会考虑这里的其他问题:

  1. 你提到你是一个“任意对象”上锁定,但_Camera似乎是什么,但 - 它是在其他地方不可预知的方式被使用的对象。 我建议做这仅用于锁定的对象,如

     object lockObject = new lockObject; lock (lockObject) { // put your synchronized code here } 
  2. Bitmap.Clone()创建这股像素数据与原来的位图的位图。 当您将转换为图像对象分配给EMGU ImageBox,您使用的是克隆,它保持位图的参考。 因此,它似乎更安全,我只需要创建一个新的位图,而不是在这种情况下使用的clone()。



Answer 2:

我认为你能避免使用在这里明确的锁都没有。 只要将位图创建操作来接收线程 - 这种方式,您将保证对原始位的所有操作都在接收线程执行。

一旦创建位图完成,传递给新位图参考阅读话题 - 把它分配给类服务它的成员。 参考分配是一个原子操作,这样保证了读取线程将看到此新值或旧的。 和而你只传授你完成创建位图后的参照,这样保证了只有读线程将永远使用它



Answer 3:

您可以使用的ManualResetEvent而不是锁来编排的读操作和写。 一个例子是这样的。

读/写主题:

while (_CaptureThreadRunning)
{
   imageBoxTrhead.WaitOne();
   readWriteThread.Reset();

   // _Camera.GetFrame writes to the Bitmap
   if (_VideoPlaying && _Camera.GetFrame(500)) 
      pbLiveFeed.Invalidate();

   readWriteThread.Set();

}
_Camera.CloseCamera(true);
_CaptureExitEvent.Set();

读/ ImageBox主题:

while (_ProcessThreadRunning)
{
   readWriteThread.WaitOne();
   imageBoxTrhead.Reset();

   //  _Camera.LiveFrame is the Bitmap
   procImage = new Image<Bgr, int>((Bitmap)_Camera.LiveFrame.Clone());          
   procImage.Draw(new Rectangle(10,20,20,15),new Bgr(Color.LightGreen), 5);

   imageBoxTrhead.Set();

   ibProcessed.Image = procImage;
   ibProcessed.Invalidate();
}
_ProcessExitEvent.Set();

凡readWriteThread和imageBoxTrhead默认情况下ManualResetEvent的对象发出信号。



文章来源: Trouble with locking an image between threads