【问题标题】:Bitmap.Save "Object is currently in use elsewhere" Threading IssueBitmap.Save“对象当前正在其他地方使用”线程问题
【发布时间】:2011-12-25 04:36:08
【问题描述】:

我有一些这样的代码:

    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 方法作为一项任务可以加快速度,但我认为我遇到了异常,因为循环的下一次迭代试图在 Save 发生时绘制到最终图像对象。我想我可以使用锁,但我担心这会减慢速度?

有修复方法还是我应该删除任务?

【问题讨论】:

  • Bitmap 类不是线程安全的,因此您不能同时从多个线程访问它。如果这意味着您必须锁定、阻止它或制作一份您可以在自己的时间保存的副本,您只需要选择一个解决方案并使用它,但您绝对不能从多个线程访问它。您还提到您在保存时正在使用它。您是否保存渲染图像?如果是这样,您可能最终应该得到一个锁或一个队列,或者您最终可能会以比它们完成的速度更快的速度结束任务。

标签: c# .net gdi+ gdi system.drawing


【解决方案1】:

确实,您不能同时从多个线程访问图像。你必须做一些同步。如果性能有问题,您可以执行以下技巧:

在您的保存方法中,锁定图像。保存到内存流,释放锁,最后保存到磁盘。 (因为磁盘 IO 很慢)。

锁定部分仅在需要实际同步时才有用。由于位图不是线程安全的,因此您不应该首先使用多个线程来访问它,因此同步应该不是问题。

【讨论】:

    【解决方案2】:

    绘制位图并将其保存在另一个线程中是非常好的,只要您不同时这样做。 GDI+ 包含一项检查,以验证您不会同时从多个线程访问位图,这就是您收到异常的原因。

    一个简单的解决方法是在开始绘制之前创建一个位图。保存后将其丢弃在任务中。但是,您必须仔细编码,如果保存位图的时间比绘图时间长,您仍然会遇到问题。你会耗尽内存。信号量可以解决这个问题,将其初始化为您喜欢的位图数量。取决于位图的大小。然后在绘图方法中调用WaitOne(),在保存方法中调用Release()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 2010-11-06
      • 2012-02-03
      • 1970-01-01
      • 2015-03-04
      • 1970-01-01
      相关资源
      最近更新 更多