我要讲的代码只是为测试我正在开发的库而编写的程序的一小部分,所以我确信它不是最优的,我也不打算改进它,因为。。。这不值得,因为它只是一个个人测试工具。
该代码将灰度图像(存储在字节[,]中)输出到面板。
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;
// ...