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() в методе сохранения.