Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Теория / Теория / ОСиСП ответы на некоторые вопросы.doc
Скачиваний:
81
Добавлен:
11.05.2015
Размер:
1.38 Mб
Скачать

Спин-блокироки.

Когда поток пытается войти в критическую секцию, занятую другим потоком, он не медленно приостанавливается, т.е. поток переходит из пользовательского режима в режим ядра (на что затрачивается около 1000 тактов процессора). Цена такого перехода чрезвычайно высока.

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

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

Для использования спин-блокировки в критической секции нужно инициализировать счетчик циклов, вызвав:

BOOL InitalizeCriticalSectionAndSpinCount( PCRITICAL_SECTION pcs, DWORD dwSpinCount);

Как и в InitializeCriticalSection, первый параметр этой функции — адрес структуры критической секции. Но во втором параметре, dwSpinCount, передается число циклов спин-блокировки при попытках получить доступ к ресурсу до перевода потока в состояние ожидания.

Этот параметр может принимать значения от 0 до 0x00FFFFFF. Учтите, что на однопроцессорной машине значение параметра dwSpinCount игнорируется и считается равным 0. Дело в том, что применение спин-блокировки в такой системе бессмысленно: поток, владеющий ресурсом, не сможет освободить его, пока другой поток «крутится» в циклах спин-блокировки.

Вы можете изменить счетчик циклов спин-блокировки вызовом:

DWORD SetCriticalSectionSpinCount( PCRITICAL_SECTION pcs, DWORD dwSpinCount);

И в этой функции значение dwSpinCount на однопроцессорной машине игнорируется.

Па мой взгляд, используя критические секции, Вы должны всегда применять спин блокировку — терять Вам просто нечего. Могут возникнуть трудности в подборе значения dwSpinCount, по здесь нужно просто поэкспериментировать. Имейте в виду, что для критической секции, стоящей на страже динамической кучи Вашего процесса, этот счетчик равен 4000.

Критические секции.

Критические секцииэто небольшой участок кода, требующий монопольного доступа к каким-то общим данным.

Критические секции не являются объектами ядра и используются для синхронизации потоков одного процесса.

Критическая секция в WinAPI описывается структурой CRITICAL_SECTION.

Критические секции – самый эффективный способ синхронизации потоков одного процесса. Критические секции не являются объектами ядра, они принадлежат единственному процессу и поэтому для синхронизации потоков, ОС не производит переключение контекста процесса (переустановка некоторых регистров процессора, в которых хранятся указатели на таблицу дескрипторов).

Переключение контекста требует перехода ОС на более высокий уровень привилегий (генерируется особая ситуация, обрабатываемая самой ОС). Эта процедура весьма длительна и всегда выполняется при работе с объектами ядра.

Критические секции отсутствуют в Unix (т.к. Unix проектировалась как система многозадачная на уровне процессов).

Перед использованием, критическая секция должна быть проинициализирована при помощи функции:

VOID InitializeCriticalSection(

LPCRITICAL_SECTION lpCriticalSection // critical section

);

Процесс, потоки которого имеют критические секции – должен инициализировать переменную этой функцией.

Для получения монопольного доступа к ресурсу или участку кода, вызываем функцию:

VOID EnterCriticalSection(

LPCRITICAL_SECTION lpCriticalSection // critical section

);

Когда работа с ресурсом завершена:

VOID LeaveCriticalSection(

LPCRITICAL_SECTION lpCriticalSection // critical section

);

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

Когда поток, захвативший критическую секцию, выходит, критическая секция освобождается и другой поток, ожидающий критическую секцию с наивысшим приоритетом, может в нее войти.

На платформе WinNT существует еще функция:

BOOL TryEnterCriticalSection(

LPCRITICAL_SECTION lpCriticalSection // critical section

);

Но она не блокируется, а возвращает FALSE, если секция занята другим потоком.