Bitmap region is already locked, multi-threaded environment

.net, c#, multithreading

Solution

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.

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.

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.

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);
        }
    }
}

This logic can also be wrapped in it's own class implementing the IDisposable interface allowing the powerful `using` construct to be used.

Problem

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. 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); } } } } } } ```

Original source