Многопоточность.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
с и AutoResetEvent
s вместо 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.. не очень подробно)