图形对象目前正在其他地方使用(尝试多线程绘制基本体)



我要讲的代码只是为测试我正在开发的库而编写的程序的一小部分,所以我确信它不是最优的,我也不打算改进它,因为。。。这不值得,因为它只是一个个人测试工具。

该代码将灰度图像(存储在字节[,]中)输出到面板。

Graphics g = pImage.CreateGraphics()
int left, right, top, bottom;
left = Math.Max(-pImage.Left, 0);
top = Math.Max(-pImage.Top, 0);
right = Math.Min(pContainer.Width - pImage.Left, Layer.Width);
bottom = Math.Min(pContainer.Height - pImage.Top, Layer.Height);
Brush[] currentBrushCatalogue = DimLights ? brushCatalogueDimmed : brushCatalogueNormal;
for (int i = left - left % ImageResolution; i < right - right % ImageResolution; i += ImageResolution)
  for (int j = top - top % ImageResolution; j < bottom - bottom % ImageResolution; j += ImageResolution)
    g.FillRectangle(currentBrushCatalogue[Layer.GetBrightness(i, j)], new Rectangle(i, j, ImageResolution, ImageResolution));

这里,

  • pImage是面板
  • Layer.GetBrightness从Layer内部的字节[,]获取值
  • brushCatalogue只是一个将字节转换为Brush对象的笔刷数组
  • ImageResolution是加快处理速度的方法(为不太详细的图像绘制更少的像素总数)

现在,我决定让它平行。由于不能从多个线程中使用Graphics对象,所以我决定绘制单独的位图,然后将所有内容混合在一起。因此我制作了这个代码:

Graphics g = pImage.CreateGraphics()
int left, right, top, bottom;
left = Math.Max(-pImage.Left, 0);
top = Math.Max(-pImage.Top, 0);
right = Math.Min(pContainer.Width - pImage.Left, Layer.Width);
bottom = Math.Min(pContainer.Height - pImage.Top, Layer.Height);
Brush[] currentBrushCatalogue = DimLights ? brushCatalogueDimmed : brushCatalogueNormal;
Bitmap[] bitmaps = new Bitmap[8];
Parallel.For(0, 8, (n) =>
                    {
                        int l = left + (right - left) * n / 8;
                        int r = left + (right - left) * (n+1) / 8;
                        bitmaps[n] = new Bitmap(r - l, bottom - top);
                        Graphics localG = Graphics.FromImage(bitmaps[n]);
                        for (int i = l - l % ImageResolution; i < r - r % ImageResolution; i += ImageResolution)
                            for (int j = top - top % ImageResolution; j < bottom - bottom % ImageResolution; j += ImageResolution)
                                localG.FillRectangle(currentBrushCatalogue[Layer.GetBrightness(i, j)], new Rectangle(i, j, ImageResolution, ImageResolution));
                    }
                    );
for (int n=0;n<8;n++)
  g.DrawImageUnscaled(bitmaps[n],left + (right-left)*n/8,top);

问题是,我仍然会出错!当我尝试填充矩形时,我会得到"对象当前正在其他地方使用。"错误。

有人能向我解释一下我做错了什么吗?我假设我在函数中创建的任何东西都会传递给Parallel。For是实例化的,这意味着每个线程都有自己的l、r和localG副本,每个副本都与自己的Graphics对象一起工作。因为很明显,否则它根本不起作用!那么,为什么"Object当前在其他地方使用"呢?如果没有其他线程接触到localG,那么localG当前如何在其他地方使用?。。。

您已经为每个子任务正确地设置了一个单独的位图/图形对象,但currentBrushCatalogue中的画笔仍然是共享的。画笔不是线程安全的,因此您需要为每个子任务创建currentBrushCatalogue的深度副本:

Parallel.For(0, 8, (n) =>
{
    var palette = currentBrushCatalogue.Select( x => x.Clone() ).Cast<Brush>().ToArray();
    // use palette instead of currentBrushCatalogue below
    int l = left + (right - left) * n / 8;
    int r = left + (right - left) * (n+1) / 8;
    // ...

相关内容

  • 没有找到相关文章

最新更新