You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程创建Bitmap调用DrawString时出现“对象正被其他地方使用”错误

问题原因与解决方案

问题出在共享的Font对象上——GDI+的Font类不是线程安全的,多个线程同时调用DrawString时共用同一个Font实例,就会触发“对象正被其他地方使用”的异常,和你每个线程独立的Bitmap、Graphics没关系。

解决步骤:

  • 每个线程创建独立的Font实例,不要共享全局的Font变量。比如在Parallel.ForEach的循环体内,用using声明自己的Font;
  • 删掉无效的lock (bitmap)——每个线程的bitmap都是独立实例,锁它根本不会和其他线程产生竞争,完全没用。

修改后的代码示例:

Parallel.ForEach(rectangles, new ParallelOptions() { MaxDegreeOfParallelism = Threads }, rect =>
{
    using Bitmap bitmap = new((int)(tileSize.Width * ChunkSize.Width), (int)(tileSize.Height * ChunkSize.Height));
    using Graphics graphics = Graphics.FromImage(bitmap);
    // 每个线程创建独立的Font实例,复制原Font的属性
    using Font threadFont = new Font(Font.FontFamily, Font.Size, Font.Style);
    
    for (int i = rect.X; i < rect.Right; i++)
    {
        for (int j = rect.Y; j < rect.Bottom; j++)
        {
            PointF Location = new PointF(tileSize.Width * (i - rect.Width), tileSize.Height * (j - rect.Height));
            
            graphics.FillRectangle(renderTiles[i, j].BackBrush, new Rectangle(Location.ToPoint().Add(new Point(5, -1)), tileSize.ToSize().Add(new Size(1, 1))));
            // 使用线程独立的Font
            graphics.DrawString(renderTiles[i, j].Ico.ToString(), threadFont, renderTiles[i, j].ForeBrush, Location.ToPoint());
        }
    }
    
    lock (pe.Graphics)
    {
        pe.Graphics.DrawImage(bitmap, rect.Location.Multiply(tileSize.ToPoint()));
    }
});

额外注意:

如果renderTiles里的ForeBrush/BackBrush是共享的可变对象(比如动态修改颜色的Brush),也可能引发线程安全问题。如果是只读的固定Brush(比如固定颜色的SolidBrush),通常没问题;如果是可变的,建议每个线程创建独立的Brush实例。

内容的提问来源于stack exchange,提问作者Doshorte Dovencio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 01:27:21