Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ВОПРОС-ОТВЕТ 2012(42)Ф.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
3.63 Mб
Скачать

§4.4.1.Критическая секция.

Важным понятием синхронизации потоков является понятие «критическая секция».

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

Чтобы исключить эффект гонок по отношению к разделяемым данным, необходимо обеспечить, чтобы в каждый момент в критической секции, связанной с этими данными, находился только один поток. Этот прием называют взаимным исключением. При этом неважно, находится этот поток в активном или в приостановленном состоянии.

Для реализации взаимных исключений используются различные способы: запрещение прерываний, блокирующие переменные, семафоры, синхронизирующие объекты ОС, рассмотренные ниже.

Вопрос 22. Способы реализации взаимных исключений путем запрещения прерываний, использования блокирующих переменных, системных вызовов. §4.4.2.Запрещение прерываний.

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

§4.4.3.Блокирующие переменные.

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

С каждым разделяемым ресурсом связывается двоичная переменная, которая принимает значение 1, если ресурс свободен (то есть ни один процесс не находится в данный момент в критической секции, связанной с данным процессом), и значение 0, если ресурс занят. На рис. 4.9 показан фрагмент алгоритма потока, использующего для реализации взаимного исключения доступа к разделяемому ресурсу D блокирующую переменную F(D). Перед входом в критическую секцию поток проверяет, свободен ли ресурс D. Если он занят, то проверка циклически повторяется, если свободен, то значение переменной F(D) устанавливается в 0, и поток входит в критическую секцию. После того, как поток выполнит все действия с разделяемым ресурсом D, значение переменной F(D) снова устанавливается равным 1.

Рис. 4.9. Реализация критической секции с использованием

блокирующих переменных

Если все потоки написаны с использованием вышеописанных соглашений, то взаимное исключение гарантируется. При этом они могут быть прерваны ОС в любой момент и в любом месте. Однако, одно ограничение на прерывания все же имеется – операция проверки и установки блокирующей переменной должна быть неделимой. Для этой цели необходимо использовать соответствующие команды проверки-установки (в процессоре Pentium это BTC, BTR, BTS) или специальные системные примитивы атомарных операций.

Поясним это. Пусть в результате проверки переменной поток определил, что ресурс свободен, но сразу после этого, не успев установить переменную в 0, был прерван. За время его приостановки другой поток занял ресурс, вошел в свою критическую секцию, но также был прерван, не завершив работы с разделяемым ресурсом. Когда управление было возвращено первому потоку, он, считая ресурс свободным, установил признак занятости и начал выполнять свою критическую секцию. Таким образом, был нарушен принцип взаимного исключения, что потенциально может привести к нежелательным последствиям.

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

Для устранения этого недостатка в ОС Windows для работы с критическими секциями используются специальные системные вызовы: EnterCriticalSection() и LeaveCriticalSection().

При входе в критическую секцию (рис. 4.10) поток выполняет системный вызов EnterCriticalSection(), в рамках которого вначале выполняется проверка блокирующей переменной необходимого ресурса. Если ресурс занят, то циклический опрос далее не выполняется, а поток переводится в состояние ожидания освобождения ресурса D. Поток, который в это время использует ресурс D, после выхода из критической секции должен вызвать системную функцию LeaveCriticalSection(), в результате чего ресурс освобождается. ОС просматривает очередь ожидающих этот ресурс потоков и переводит поток, ожидающий событие D, в состояние «готовность».

Рис. 4.10. Реализация критической секции с использованием

системных функций