多线程System.Windows.Graphics [英] Multithreading System.Windows.Graphics

查看:115
本文介绍了多线程System.Windows.Graphics的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当然知道我不能从不同的线程绘制相同的 Graphics c>对象,但是我也无法绘制不同的 Graphics 在不同线程中的对象



考虑以下控制台程序:

  class程序
{
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();
抽屉[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(Graphics 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();



code
$ b

程序创建一个 Bitmap ,然后使用 Graphics 对象在其上绘制随机椭圆,该对象也是从<$ c


$ b $ p $由于需要构建 .net2 ,多线程是使用 Thread s和 AutoResetEvent s而不是TPL实现的。



程序执行时不会引发异常,但它会连续执行。使用 n 线程将执行时间乘以 n ,很明显看到使用任务管理器只有一个内核使用。



需要注意的是,这些内容都不会绑定到任何UI元素



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

解决方案

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


是的,你可以看到很多红色(块状)绿色斑点(执行)。线程轮流进入内部GpGraphics :: RenderDrawPath()函数内部获取的关键部分。更大的绿色斑点是程序实际绘制线条的位置(我用DrawRectangle替换了DrawEllipse并摆脱了Random调用)。

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



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

I know of course that I can not draw onto the same Graphics object from different threads, but is it also true that I can not draw to different Graphics objects in different threads?

Consider the following console program:

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();
        }
    }
}

The program creates a Bitmap in each thread and proceeds to draw random ellipses on it using a Graphics object, also generated per thread from the Bitmap.

Due to a requirement to build for .net2 the multithreading is implemented using Threads and AutoResetEvents instead of TPL.

The program executes without throwing an exception, but it executes serially. Using n threads multiplies execution time by n and it is clear to see using the task manager that only one core is being used.

Important to take note that none of this is tied to any UI element.

What is going on here? Is the Graphics object locking on a static object?

解决方案

Here's a screen-shot of the concurrency analyzer I used to see what's going on with these threads:

Yes, you can see lots of red (blocking) with flecks of green (execution). The threads are taking turns entering a critical section that's acquired inside the internal GpGraphics::RenderDrawPath() function. The larger blobs of green is where the program actually drew the lines (I replaced DrawEllipse with DrawRectangle and got rid of the Random call).

There is some concurrency, you can for example see the RenderDrawPath() call being overlapped by the code that renders the anti-aliased lines, overall cpu load is around 35%. But there isn't much of it.

Nothing you can do about it of course. You get ahead by overlapping the logic in your own program to decide what to draw with the GDI+ calls. Which will normally happen, the test is too synthetic.

这篇关于多线程System.Windows.Graphics的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆