multithreading系统.Windows.Graphics

我当然知道我不能从不同的线程绘制到同一个Graphics对象,但是我也不能在不同的线程中绘制到不同的 Graphics对象吗?

考虑以下控制台程序:

 class Program { static ThreadDrawer[] drawers; static void Main(string[] args) { int numThreads = 8; drawers = new ThreadDrawer[numThreads]; for (int i = 0; i < numThreads; i++) { drawers[i] = new ThreadDrawer(); drawers[i].Start(); } for (int i = 0; i < numThreads; i++) { drawers[i].Wait(); } Console.WriteLine("Complete."); Console.ReadKey(); } class ThreadDrawer { private Thread thread; private AutoResetEvent resetEvent; public ThreadDrawer() { thread = new Thread(DrawRandomCircles); resetEvent = new AutoResetEvent(false); } public void Start() { thread.Start(); } public void Wait() { resetEvent.WaitOne(); } public void DrawRandomCircles() { Random r = new Random(Environment.TickCount); using (Bitmap b = new Bitmap(1000, 1000)) using (Graphics g = Graphics.FromImage(b)) { for (int i = 0; i < 100000; i++) { g.DrawEllipse(Pens.Red, new Rectangle(r.Next(1000), r.Next(1000), 200, 200)); } } resetEvent.Set(); } } } 

程序在每个线程中创建一个Bitmap ,并继续使用Graphics对象在其上绘制随机椭圆,该对象也是从Bitmap每个线程生成的。

由于需要构建.net2 ,因此使用ThreadAutoResetEvent而不是TPL实现multithreading。

程序执行时不会抛出exception,但它会串行执行 。 使用n线程将执行时间乘以n ,很明显看到使用任务管理器只使用了一个核心。

重要的是要注意, 这些都不与任何UI元素相关联

这里发生了什么? Graphics对象是否锁定在静态对象上?

这是我用来看看这些线程发生了什么的并发分析器的屏幕截图:

在此处输入图像描述

是的,你可以看到许多带有绿色斑点(执行)的红色(阻挡)。 线程轮流进入在内部GpGraphics :: RenderDrawPath()函数内部获取的临界区。 较大的绿色斑点是程序实际绘制线条的地方(我用DrawRectangle替换DrawEllipse并摆脱了随机调用)。

有一些并发性,例如,您可以看到RenderDrawPath()调用与呈现消除锯齿线的代码重叠,整体cpu负载约为35%。 但是没有多少。

当然,你无能为力。 您可以通过重叠自己程序中的逻辑来决定使用GDI +调用绘制什么。 这通常会发生,测试过于合成。

似乎锁定发生在非托管代码中,在GDI +库中(不幸的是,这种行为在官方文档中没有提到)。

类似的问题: 并行化GDI +图像大小调整.net

我不是100%确定..但是,是的, Graphics类中有一个private static锁定对象。 它似乎只是从GetHalftonePalette锁定,而GetHalftonePalette只是在Graphics对象中初始化Bitmap被调用。 看起来这可能是争用的原因。

(注意:使用ILSpy 5分钟后的初步调查结果..不是很深入)