Очередь критического раздела

В критических разделах 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, как в моем случае? Оба потока имеют нулевой приоритет.

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

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


person riv    schedule 04.04.2013    source источник
comment
почему viewer->finish не защищен от одновременного доступа? Он хоть летучий ??   -  person UmNyobe    schedule 04.04.2013
comment
Ваш while цикл блокируется сразу после разблокировки, что не помогает.   -  person Roger Rowland    schedule 04.04.2013
comment
Каковы приоритеты ваших основных потоков и потоков рендеринга?   -  person Mladen Janković    schedule 04.04.2013
comment
Потому что просмотрщик ›финиш изменяется только основным потоком. Оба приоритета равны нулю. Я предположил, что это может быть так, но не следует ли хотя бы проверить, пытается ли какой-то другой поток взять на себя управление, прежде чем снова войти в критический раздел?   -  person riv    schedule 04.04.2013


Ответы (4)


В более старых версиях Windows было гарантировано получение критических разделов в порядке очереди. Начиная с Windows Server 2003 SP1, этого больше не происходит.

Из MSDN:

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

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

person NPE    schedule 04.04.2013
comment
Хорошо, это то, чего я хотел избежать, но спасибо. Строка If all the calling threads have the same priority, a first-in, first-out (FIFO) basis is used after the current thread leaves the critical section. в MSDN меня смутила. - person riv; 04.04.2013
comment
@riv: Я погуглил цитату, и единственное место, где я вижу, она говорит о Windows Mobile 6.5. Если ваш вопрос касается Windows Mobile, то вам следует так сказать. - person NPE; 04.04.2013
comment
Да, это была моя ошибка, я привык, что MSDN встроен в Visual Studio, а теперь, когда у меня его нет, я просто гуглил любую нужную мне функцию и не всегда замечаю необычную платформу. - person riv; 04.04.2013

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

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

person spiritwolfform    schedule 04.04.2013

Согласно 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, это могло произойти.

person bash.d    schedule 04.04.2013
comment
Ой, я только что понял, что смотрю на Windows Mobile MSDN = ( - person riv; 04.04.2013

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

person Mladen Janković    schedule 04.04.2013