Многопоточность.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 многопоточность реализована с использованием Threadс и AutoResetEvents вместо TPL.

Программа выполняется без исключения, но выполняется последовательно. С помощью n потоки умножают время выполнения на n и с помощью диспетчера задач ясно видно, что используется только одно ядро.

Важно отметить, что ничего из этого не связано с каким-либо элементом пользовательского интерфейса.

Что здесь происходит? Это Graphics блокировка объекта на статическом объекте?

3 ответа

Решение

Вот снимок экрана анализатора параллелизма, который я использовал, чтобы увидеть, что происходит с этими потоками:

Да, вы можете увидеть много красного (блокирование) с зелеными пятнами (исполнение). Потоки по очереди входят в критическую секцию, полученную во внутренней функции GpGraphics::RenderDrawPath(). Большие зеленые пятна - это то место, где программа фактически рисовала линии (я заменил DrawEllipse на DrawRectangle и избавился от вызова Random).

Существует некоторый параллелизм, например, вы видите, что вызов RenderDrawPath () перекрывается кодом, который отображает сглаженные строки, общая загрузка ЦП составляет около 35%. Но это не так много.

Ничего не поделаешь, конечно. Вы продвигаетесь вперед, перекрывая логику в своей собственной программе, чтобы решить, что рисовать с помощью вызовов GDI+. Что обычно бывает, тест слишком синтетический.

Кажется, что блокировка происходит в неуправляемом коде внутри библиотеки GDI+ (к сожалению, это не упоминается в официальных документах).

Аналогичный вопрос: распараллеливание GDI+ изменение размера изображения.net

Я не уверен на 100%.. но да, есть private static блокировка объекта в Graphics учебный класс. Кажется, он заблокирован только от GetHalftonePaletteкоторый, в свою очередь, называется всякий раз, когда Bitmap инициализируется в пределах Graphics объект. Казалось бы, это может быть причиной раздора.

(Примечание: первые результаты после 5 минут использования ILSpy.. не очень подробно)

Другие вопросы по тегам