Критический раздел изменение поведения в Windows 2003 SP1


Сегодня я наткнулся на это в MSDN:

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

Сначала я подумал, что WTF?! - Я всегда предполагал, что нити будут приобретать критическую секцию в том порядке, в котором они пытались ее получить. Хотя это кажется странным большим изменением в поведение для пакета обновления, пакет обновления был для серверной версии Windows, и Vista была в стадии разработки в то время, я полагаю.

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

Тем не менее, это предположение, которое я сделал и сейчас оцениваю мой код, чтобы убедиться, что ни один случай FIFO reliance не является проблемой.

Были ли у кого-нибудь реальные проблемы с этим? Хотя порядок потоков, получающих критическую секцию, не гарантируется FIFO, обычно это не FIFO? Если нет обычно FIFO (или близко к FIFO), кто-нибудь знает, как долго поток может ждать сильно оспариваемого критического раздела? Если это поток с низким приоритетом, означает ли это, что он может ждать почти бесконечно, если всегда есть более высокий приоритетный поток пытается получить критическую секцию (даже если низкоприоритетный поток был давно следующим в очереди, если FIFO был привязан)? Существует ли предохранитель, предотвращающий этот сценарий, или необходимо полагаться на вторичный объект синхронизации?

Конечно, это действительно имеет значение только на действительно сильно оспариваемом критическом участке. Не знаю, может быть, я придаю этому слишком большое значение... но что-то меня в этом беспокоит. Любое понимание ценится. Спасибо ;)
2 3

2 ответа:

По моему опыту критические секции Никогда не были FIFO (возможно, команда doc пересекла свои провода, сказав, что это новое в 2003 году). И да, это может привести к резьбовому голоданию, которое мы уже много раз наблюдали. Если вам нужен ФИФО, вам нужен мьютекс.

Мьютексы являются объектами ядра, и поэтому приобретать их дороже, чем кольцо 3 оптимистической критической секции. Но FIFO-это не одна из тех вещей, которые вы можете (или должны) обязательно выбросить из головы как ненужные, и это не должно быть ничего общего с "иерархией" потоков (что бы это ни было-Означает ли это приоритет?). 1000 потоков одинакового приоритета, попав в одну блокировку, легко вызовут голод.

Это первый раз, когда я слышу это, и когда я думаю об этом, это не кажется проблемой.

Если я правильно понял ::

Олдуэй:

Thread A acquired the CritSec
Thread B waiting for the CritSec , tried to acquire it at time t
Thread C waiting for the CritSec , tried to acquire it at time t + dt

When Thread A releases the CritSec, OS ensures that Thread B acquires it.

NewWay:

Thread A acquired the CritSec
Thread B waiting for the CritSec , tried to acquire it at time t
Thread C waiting for the CritSec , tried to acquire it at time t + dt

When Thread A releases the CritSec, OS may choose any Thread to acquire it. So, it may be Thread B or C that will acquire it after A releases it.
Я никогда не предполагал (и не думаю, что кто-то еще предполагал), что потоки, ожидающие CritSec, получат его в том порядке, в котором они хотели его получить.

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