Bitmap.Save "Объект в настоящее время используется в другом месте" Проблема с потоками

У меня есть такой код:

    public void SaveImage(int Counter)
    {
        var task = Task.Factory.StartNew(() =>
        {
            var image = FinalImage;
            if (image != null)
            {
                image.Save(FinalImageSaveLocation + "test" + Counter + ".bmp");
            }
        }, TaskCreationOptions.PreferFairness);
    }

У меня есть цикл for для создания x количества изображений с использованием аналогичного кода ниже:

for(int i = 0; i < 100; i++)
{
  Pencil.DrawImage(image, x, y); //Pencil is created at a initialisation stage
  SaveImage(i);                  //by Pencil = Graphics.FromImage(FinalImage);
}

Я подумал, если поместить метод SaveImage в качестве задачи, это ускорит процесс, но я предполагаю, что получаю исключение, потому что следующая итерация цикла пытается нарисовать конечный объект изображения, пока происходит сохранение. Я думаю, я мог бы использовать замок, но я боюсь, что это замедлит ход событий?

Есть ли исправление или я должен просто удалить задачу?

2 ответа

Решение

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

В вашем методе сохранения получите блокировку изображения. Сохраните в поток памяти, снимите блокировку и, наконец, сохраните на диск. (поскольку дисковый ввод-вывод очень медленный).

Часть блокировки полезна только при необходимости фактической синхронизации. Поскольку растровое изображение не является потокобезопасным, вы не должны получать к нему доступ, используя в первую очередь несколько потоков, и, следовательно, синхронизация не должна быть проблемой.

Рисовать в растровое изображение и сохранять его в другом потоке - это прекрасно, если вы не делаете это одновременно. GDI+ содержит проверку, чтобы убедиться, что вы не обращаетесь к растровому изображению более чем из одного потока одновременно, поэтому вы получаете исключение.

Простой обходной путь - создать новое растровое изображение перед началом рисования. Утилизируйте его в задании после его сохранения. Вы должны тщательно это кодировать, у вас все равно будет проблема, если сохранение растрового изображения займет больше времени, чем рисование. Вам не хватит памяти. Семафор может решить эту проблему, инициализируя его тем количеством растровых изображений, с которым вам удобно. Зависит от размера растрового изображения. Затем вызовите WaitOne() в методе рисования, Release() в методе сохранения.

Другие вопросы по тегам