问题描述
我正在使用一个通过多个线程调用主函数的API.我试图通过该函数访问另一个类中的位图并从中进行写入,但是即使将其设置为使用对象的完全不同的实例后,我仍遇到InvalidOperationException:位图区域已被锁定.
I'm working in an API that calls the main function through multiple threads. I'm trying to access through that function a Bitmap in another class and write from it, but even after setting it to use completely different instance of the object I am experiencing an InvalidOperationException: Bitmap region is already locked.
我试图在主函数中以及在调用Bitmap.LockBits(...)的地方锁定代码.是的,我完成后会调用UnlockBits.
I've tried locking code in the main function and where Bitmap.LockBits(...) is being called. Yes, UnlockBits is being called when I'm done.
/* Part of Class B */
public Surface imageSurface //Surface is a field of pixels, more or less.
{
get
{
if (_CurrImage != null && _imageSurface == null)
{
_imageSurface = Surface.CopyFromBitmap(_CurrImage);
return Surface.CopyFromBitmap(_imageSurface.CreateAliasedBitmap());
}
else
{
Surface clearPixel = new Surface(1, 1);
clearPixel[0, 0] = ColorBgra.FromBgra(255, 255, 255, 0);
return clearPixel;
}
}
}
/* the "main" function, Class A */
public override void Render(ClassBPrototype parameters, ...)
{
ClassB token = (ClassB)parameters; // Here we go again~!
...
Surface ourSurface = dstArgs.Surface;
if (token.imageSurface.Size != null)
{
ourSurface = token.imageSurface;
}
lock(typeof(ClassA))
{
for (int lRectangleIndex = ...)
{
Rectangle lRectangle = rois[lRectangleIndex];
for (int y = ...)
{
surfaceY = (ourSurface.Height / 2) - (y - (int)CenterY);
for (int x = ...)
{
surfaceX = (ourSurface.Width / 2) - (x - (int)CenterX);
if (surfaceX >= 0 && surfaceX < ourSurface.Width && surfaceY >= 0 && surfaceY < ourSurface.Height)
{
dstArgs.Surface[x, y] = ourSurface[surfaceX, surfaceY];
}
else
{
dstArgs.Surface[x, y] = ColorBgra.FromBgra(255, 255, 255, 0);
}
}
}
}
}
}
推荐答案
问题很可能是共享资源-位图-不受代码示例中的锁保护.锁需要包装LockBits
和UnlockBits
调用,以有效防止同时访问Bitmap
实例.
The problem is most likely that the shared resource - the Bitmap - is not protected by the lock in the code-example. The lock needs to wrap both the LockBits
and UnlockBits
calls to be effective against simultaneous access to the Bitmap
instance.
在这种情况下,我建议使用实际的Bitmap
实例作为锁定对象,因为再次从不同线程同时访问时,需要再次保护该实例.
In this case I would advice to use the actual Bitmap
instance as lock object since this is what needs to be safeguarded agains simultaneous access from diffrent threads.
仅当在静态方法中使用锁时,才建议锁定typeof(ClassA)
.
Locking on typeof(ClassA)
is only recommended when using locks inside static methods.
请注意,锁是互斥锁,当一个线程已获得该锁时,其他线程将被挂起.如果将大部分时间花费在锁内部,那么拥有多个线程将不会或几乎不会带来并行化好处.
Please note that locks are mutual exclusion locks and the other threads will be suspended while one single threads has aquired the lock. If most time is spent inside the lock no or little parallellization benefits will come from having multiple threads.
在发生异常的情况下,锁定将通过锁定构造的设计来释放,而通常不会调用UnlockBits
方法.如果可以引发并捕获异常,我建议从finally块调用UnlockBits
方法.像这样:
In case of an exception the lock will be released by design of the lock construct, while the UnlockBits
method will typically not be called. If an exception can be thrown and catched I would recommend calling the UnlockBits
method from a finally block. Something like this:
private Bitmap _bitmap;
public void foo()
{
lock (_bitmap)
{
BitmapData data;
try
{
data = _bitmap.LockBits(area, ImageLockMOde.ReadOnly, pixelFormat);
UseBitmapData(data);
}
finally
{
_bitmap.UnlockBits(data);
}
}
}
此逻辑也可以包装在自己的类中,该类实现IDisposable接口,从而可以使用功能强大的using
构造.
This logic can also be wrapped in it's own class implementing the IDisposable interface allowing the powerful using
construct to be used.
这篇关于位图区域已被锁定,多线程环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!