Выбрать главу

Таким образом, в случае однопроцессорных систем объекты CS эффективны тогда, когда высока вероятность их разблокирования, что иллюстрирует вариант CS программы 9.1. Преимущества SMP-систем обусловлены тем фактом, что пока ожидающий поток выполняет цикл ожидания, управляемый спин-счетчиком, объект CS может оказаться разблокированным потоком, выполняющимся на другом процессоре.

Далее будет показано, как устанавливать значения спин-счетчиков и настраивать приложения путем выбора наиболее оптимальных значений. Еще раз подчеркнем, что спин-счетчики оказываются полезными лишь в случае SMP-систем; на однопроцессорных системах они не используются.

Установка значений спин-счетчиков

Спин-счетчики CS могут устанавливаться на стадии инициализации объектов CS или динамическим путем. В первом случае функция InitializeCriticalSection заменяется функцией InitializeCriticalSectionAndSpinCount, в которой добавлен параметр счетчика. В то же время, способа, позволяющего считать значение спин-счетчика, не существует.

VOID InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwCount) 

Значение спин-счетчика можно в любой момент изменить. 

VOID SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwCount) 

В документации Microsoft говорится о том, что рекомендуемым для управления кучей значением спин-счетчика является 4000. Однако оптимальное значение зависит от свойств приложения, и поэтому спин-счетчики должны настраиваться индивидуально для каждого приложения, выполняющегося в реалистическом SMP-окружении. Наилучшее значение будет различным в зависимости от количества процессоров, характера приложения и тому подобного.

На Web-сайте книги находится программа TimedMutualExclusionSC. Эта программа представляет собой видоизмененный вариант уже знакомой вам программы TimedMutualExclusion, в котором значение спин-счетчика указания в качестве параметра командной строки. Вы можете запустить эту программу на своей машине для приблизительной оценки того, какое значение спин-счетчика будет наиболее приемлемым для выполнения того или иного из вариантов тестовых программ на доступных вам SMP-системах, что и предлагается сделать в упражнении 9.2. 

Дросселирование семафора для уменьшения состязательности между потоками

Слишком большое количество потоков, соревнующихся между собой за право владения единственным ресурсом, например, мьютексом или объектом CS, могут стать причиной снижения производительности как в однопроцессорных, так и в многопроцессорных системах. В большинстве случаев негативное влияние некоторых факторов на производительность может быть сведено к минимуму за счет использования спин-счетчиков, тщательного выбора типа объектов синхронизации или перестройки структуры программы с целью увеличения степени детализации блокировок и длительности периодов блокирования.

Если ни один из этих методов не дает желаемого улучшения, то могло бы показаться, что нет иного выхода, кроме как уменьшить количество потоков, но при этом вы будете вынуждены заставлять одиночные потоки мультиплексировать те операции, которые естественнее было бы распределить между несколькими потоками. Выход из этой ситуации обеспечивают семафоры, которые дают возможность сохранить естественную многопоточную модель, но вместе с тем свести к минимуму количество активных потоков, конкурирующих между собой. Такое решение является концептуально простым, и его можно без труда включить в любую существующую прикладную программу, например TimedMutualExclusion. В системе "хозяин/рабочий" решение, носящее название "дросселя" семафора (semaphore throttle), использует следующую методику:

• Главный поток создает семафор с небольшим, например 4, максимальным значением параметра, представляющего максимально допустимое количество активных потоков, которое, например, можно принимать равным количеству процессоров, установленных в системе, для обеспечения приемлемой производительности. Начальное значение счетчика семафора также следует установить равным максимальному значению. Это число можно сделать параметром и подбирать его оптимальное значение экспериментальным путем так же, как и в случае спин-счетчиков. Другим возможным значением этого параметра может служить количество процессоров, которое может быть определено во время выполнения программы (см. следующий раздел).