Критическая секция очереди

В критических секциях Windows нет концепции очереди?

У меня есть следующий цикл рендеринга в отдельном потоке:

while (!viewer->finish)
{
EnterCriticalSection(&viewer->lock);
viewer->renderer->begin();
viewer->root->render(viewer->renderer);
viewer->renderer->end();
LeaveCriticalSection(&viewer->lock);
}

Основной поток выполняет обработку сообщений, и когда я обрабатываю события мыши, я пытаюсь войти в тот же критический раздел, но по какой-то причине он запускает поток рендеринга еще на тысячу итераций (около 10 секунд), прежде чем основной поток, наконец, входит критический раздел. Что является причиной этого — даже если нет «очереди» для входа в раздел, не должно ли это быть больше как 50/50, а не 99,9 / 0,1, как в моем случае? Оба потока имеют приоритет 0.

И какой хороший способ добавить такую ​​очередь? Достаточно ли простого флага, например bDoNotRenderAnything?

Редактировать: решение в моем случае состояло в том, чтобы просто добавить объект события (вероятно, будет работать и логическая переменная), который устанавливается каждый раз, когда обработчику сообщений требуется доступ к критическому разделу, и сбрасывается после его использования. Средство визуализации не входит в раздел, если установлена ​​переменная / событие. Таким образом, обработчику сообщений не придется ждать более одной итерации рендеринга.

2

Решение

В более старых версиях Windows критические разделы гарантированно приобретались в порядке поступления. Это больше не относится к Windows Server 2003 с пакетом обновления 1 (SP1).

От MSDN:

Начиная с Windows Server 2003 с пакетом обновления 1 (SP1), потоки, ожидающие в критической секции, не получают критическую секцию в порядке очереди. Это изменение значительно повышает производительность для большей части кода. Однако некоторые приложения зависят от порядка «первым пришел — первым вышел» (FIFO) и могут плохо работать или не работать вообще в текущих версиях Windows (например, приложения, которые использовали критические секции в качестве ограничителя скорости). Чтобы ваш код продолжал работать правильно, вам может потребоваться добавить дополнительный уровень синхронизации. Например, предположим, что у вас есть поток производителя и потребительский поток, которые используют объект критического раздела для синхронизации своей работы. Создайте два объекта события, по одному для каждого потока, чтобы указать, что он готов для продолжения другого потока. Поток потребителя будет ждать, пока производитель сообщит о своем событии, прежде чем войти в критическую секцию, а поток производителя будет ждать, пока поток потребителя не сообщит о своем событии, прежде чем войти в критическую секцию. После того, как каждый поток покидает критическую секцию, он сообщает о своем событии, чтобы освободить другой поток.

Windows Server 2003 и Windows XP: Потоки, ожидающие в критическом разделе, добавляются в очередь ожидания; они просыпаются и обычно получают критический раздел в том порядке, в котором они были добавлены в очередь. Однако, если потоки добавляются в эту очередь с достаточно высокой скоростью, производительность может ухудшиться из-за времени, которое требуется для пробуждения каждого ожидающего потока.

4

Другие решения

Потоки, ожидающие в критической секции, не получают критическую секцию в порядке поступления заявок (MSDN)

Большую часть времени ваш рабочий поток владеет блокировкой, потому что он повторно блокируется сразу после снятия блокировки. Таким образом, у другого потока не так много времени, чтобы проснуться и захватить блокировку, когда она свободна.

3

В соответствии с MSDN

There is no guarantee about the order in which waiting threads
will acquire ownership of the critical section.

поэтому он не уверен, в каком порядке будут выполняться потоки. И если ваш довольно короткий

viewer->renderer->begin();
viewer->root->render(viewer->renderer);
viewer->renderer->end();

Последовательность удается восстановить CriticalSection более того, это может случиться.

1

Вы можете попробовать быстро исправить с помощью SwitchToThread вызовите в вашем цикле рендеринга (после определенного количества итераций), хотя я сомневаюсь, что это будет достаточно хорошим решением.

0