Растровая область уже заблокирована, многопоточная среда - PullRequest
4 голосов
/ 12 октября 2009

Я работаю в API, который вызывает основную функцию через несколько потоков. Я пытаюсь получить доступ через эту функцию к растровому изображению в другом классе и написать из него, но даже после установки для него использования совершенно другого экземпляра объекта я испытываю исключение InvalidOperationException: область растрового изображения уже заблокирована.

Я пытался заблокировать код в основной функции и где вызывается Bitmap.LockBits (...). Да, UnlockBits вызывается, когда я закончу.

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

                    }
                }
            }
        }
    }

1 Ответ

4 голосов
/ 03 февраля 2011

Скорее всего, проблема в том, что общий ресурс - растровое изображение - не защищен блокировкой в ​​примере кода. Блокировка должна обернуть вызовы LockBits и UnlockBits, чтобы обеспечить одновременный доступ к экземпляру Bitmap.

В этом случае я бы посоветовал использовать фактический экземпляр Bitmap в качестве объекта блокировки, поскольку это то, что необходимо защищать от одновременного доступа из разных потоков.

Блокировка на typeof(ClassA) рекомендуется только при использовании блокировок внутри статических методов.

Обратите внимание, что блокировки - это взаимоисключающие блокировки, и другие потоки будут приостановлены, пока одна нить приобрела блокировку. Если большая часть времени будет потрачена внутри блокировки, параллелизация не принесет никаких преимуществ, если у вас будет несколько потоков.

В случае исключения блокировка будет снята с помощью конструкции блокировки, тогда как метод UnlockBits обычно не вызывается. Если исключение может быть сгенерировано и перехвачено, я бы рекомендовал вызвать метод UnlockBits из блока finally. Примерно так:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...