Ю. Вахалия - UNIX изнутри (2003) (1114670), страница 71
Текст из файла (страница 71)
Р1 — зто критический участок кода, защищенный семафором. На стадии а семафор удерживается нитью Н2, а нить НЗ находится в режиме его ожидания. Нить Н1 выполняется на другом процессоре системы, в то время как Н4 находится в очереди планирования. Теперь представьте, что Н2 завершает выполнение критической секции и освобождает семафор. Тогда она разбудит нить НЗ и перенесет ее в очередь планировщика. Теперь семафор удерживает нить НЗ (как зто показано на рис. 7.7, 6). Очередь планирования Удержание Рнс. 7.7. Пример формирования конвоев Затем выполнение критического участка кода необходимо начать нити Н1. Так как семафор в текущий момент удерживается нитью НЗ, Н1 будет заблокирована и освободит процессор П1.
Система направит нить Н4 на выполнение на этом процессоре. Таким образом, на этапе в семафор удерживает нить НЗ, Н1 ожидает его освобождения, а нити Н2 и Н4 могут выполняться до тех пор, пока сами не освободят занимаемые ими процессоры. Проблема возникает именно на этой стадии. Семафор был присвоен нити НЗ, но она в данный момент не выполняется и, следовательно, не находит. ся в критической области.
В результате нить Н1 должна быть заблокирована в ожидании семафора, несмотря на то, что ни одна из нитей не вьпюлняет 7.6. Простая блокировка 305 критичный участок кода. Семантика команд работы с семафорами предоставляет ресурсы по принципу: «кто первым пришел, тот и будет обслужен». Такой подход приводит к большому количеству ненужных переключений контекста. Представьте ситуацию, в которой вместо семафора используется обьекгп глигех (взаимное исключение).
Тогда на стадии 6 нить Н2 должна освободить объект и разбудить НЗ. Но последняя не является на этой стадии владельцем объекта. Следовательно, на следующем этапе объект будет пытаться получить нить Н1, что искл!очит переключение контекста. ПРИМЕЧАНИЕ мц!ех, или взаимное исключение (сокращение от пш!ца! ехс!цшоп !оса), является общим термином, обозначающим любой примитив, приводящий к семантике эксклюзивного доступа.' Иэ сказанного можно сделать вывод, что наиболее предпочтительным является применение вместо единого монолитного объекта высшего уровня простых в обращении элементов низшего уровня. Именно этой идеей руководствуются разработчики ядра современных многопроцессорных систем.
Следующие разделы будут посвящены описанию механизмов низшего уровня, создающих вместе гибкую систему синхронизации. 7.6. Простая блокировка Простейшим элементом блокировки является объект, называемый г(иклической блокировкой (вр!н 1оск), а иногда — простой блокировка!2 (гйгпр!е 1ос)г) или простым взаимным исключением (знпр1е ншгех). Если ресурс защищен ' Согласно Р051Х, как семафоры, так и взаимные исключения являются объектами синхронизации, но первые представляют собой минимальный примитив, на котором основываются комплексные механизмы синхронизации, а вторые — не что иное как обьекты синхронизации, используемые лля обеспечения погледоэптельггого доступа множества нитей к разделяемым данным.
Послелнее определение не отличается в своей основе от такового для циклической (эрш) блокировки. Следуя логике примечания и примеру в 7.5.1, семафоры также можно считать взаимными исключениями. Отсюда нетрудно сделать вывод, что семафоры и простые блокировки можно причислить к объектам шнгех. И наоборот, применяемые в иных ОС (тхЖог)гэ) целочисленные семафоры (со счетчиком) нельзя назвать семафорами, если ориентнроватьсн на РОЕЦХ (слелование которому — пело лобровольное). И уж тем более такими нельзя назвать шнщр!е»ча!г (пшхва!г) семафоры 05/2, аналогичные наборам семафоров в ()Ы!Х, используемые для управления именованными каналами.
В этой же ОС имеется понятие семафора взаимно~о исключения (все тот же шнгех). Или посмотрите далее в начале раздела 7.6... Таким образом, реализация объекта, тоесть семантика обращений к нему, и является главным его идентификатором. Например, если в 5умеш '»Г для управления несколькими семафорами требуется один вызов, а не несколько, то это — один объект. В этом отношении Р051Х недостаточно учитывает ситуацию на местах, что логично, поскольку»авторы стандартов не пишут компьютерных программ». Но с другой стороны, программисты часто, пытаясь»договориться между собой», используют жаргонные термины, например чмьютеке», поэтому дальше мы будем придерживаться более грамотного »взаимного исключениям — Ирнм.
Ред. 306 Глава 7. Синхронизация. Многопроцессорные системы при помощи этого механизма, то нить, пытающаяся получить доступ к такому ресурсу, перейдет в режим занятого ожидания (выполнения определенного цикла) до тех пор, пока объект не будет освобожден. Взаимоблокировкв обычно представляет собой переменную, имеющую значение О, если ресурс доступен, и значение 1, если он занят. Отслеживание переменной происходит внутри цикла, основанного на одной из неделимых операций, поддерживаемых конкретной аппаратной архитектурой, например при помощи команды тестирования и установки, Ниже представлен пример использования взвимоблокировки.
Он основан на том, что операция 1е51 ап(( ве1() возвращает предыдущее значение объекта. Листинг 7.5. Применение циклической блокировки чотт) 5(ттп 1оск (зртп)оск т *5) ( нщ 1е (тезт апб зев(5 Р = О) /* ресурс занят *( ; У* випопнение цикла до тех пор, пока ресурс не освободится *У ) чотт) зртп вп1оск (5ртп1оск т 5) (5 = 0; ) Несмотря на простоту алгоритма, в нем имеются определенные недостатки. На многих машинах операция 1е51 апт( ве1() блокирует шину памяти. Таким образом, длительный цикл может привести к занятию шины одной нитью— и, следовательно, к существенному уменьшению производительности системы. Решить проблему можно при использовании двух циклов: внешний цикл предназначен для проверки переменной, если проверка не проходит успешно, внутренний цикл будет ждать обнуления значения. Простейшая проверка условия во внутреннем цикле не требует занятия шины памяти.
Реализация взаимоблокировки при помощи двух циклов показана в листинге 7.6. Листинг 7.6. Более корректный способ применения простой блокировки чо!О 5ртп тоси (5ртп1оск т *5) ( нн11е (тезв апт) вес(5)!= О) т* ресурс занят *( нит1е (*5 != О) : т'* свидание освобождения ресурса *т' ) чотт) вртп ип1оск (зртп1оск С 5) (5 - 0; ) 7.6 . 1 . Применение простой блокировки Наиболее важным свойством простой блокировки является продолжение выполнения нити (или использования процессорного времени) во время ожидания освобождения ресурса.
Следовательно, такую блокировку можно применять только для коротких промежутков ожидания. В частности, эти операции не следует производить совместно с блокировкой нитей. Рекомендуется также приостановить обработку прерываний до вызова объекта простой блокировки, что гарантирует уменьшение общей продолжительности ожидания.
7.7. Условные переменные 307 Главным условием применения простой блокировки является использование ресурса другой нитью (выполняюшейся на другом процессоре), в то время как первая нить находится в режиме ожидания ресурса. Следовательно, использование таких объектов возможно только в многопроцессорных архитектурах. На однопроцессорной машине нить, находящаяся в цикле ожидания освобождения ресурса, не выйдет из этого цикла никогда. Однако многопроцессорные алгоритмы должны работать корректно при л)обом количестве процессоров в системе, в том числе и в случае одного СРП. Для этого необходимо ограничить применение правила занятия процессора нитью прн ожидании ресурса. В частности, на однопроцессорных машинах ни одна нить не должна иметь право входить в режим ждущего цикла при применении взаимоисключения. Основным достоинством объектов простой блокировки является невысокое использование ресурсов системы.
Блок не содержит никакой информации внутри себя, а операции занятия и освобождения объекта требуют выполнения всего лишь одной команды для каждой из пих. Простая блокировка идеально подходит для блокировки структур данных, к которым производятся частые обращения, например для удаления элемента из двунаправленного связанного списка или проведения операции загрузки, изменения и сохранения переменной. Из сказанного можно сделать вывод, что применение объектов простой блокировки наиболее целесообразно для защиты тех структур данных, которые не нуждались в таковой в однопроцессорных системах.
Однако простые объекты блокировки применяются и для более сложной зашиты, что будет продемонстрировано в следуюгцих разделах главы. Например, они могут быть использованы совместно с семафорами для подтверждения неделимости операции (листинг 7.7.). Листинг 7.7. Применение простых блокировок для организации доступа к двунаправленному связанному списку 5р1П1ось Г 1155; 5р1п 1ось 161155); Пев->тоги->Ьаск = 1тев->Ьаск: Пев->Ьаск->тоги = 5вев->1огн; 5р)п ип1осХ 1$1155): 7.7. Условные переменные Условные переменные представляют собой более сложный механизм блокировки, основанный на логике предикатов (выражения, имеющие значения ТК() Е и БАРБЕ). Такие переменные позволяют нити приостановить работу в ожидании совместно используемых ресурсов и возобновить выполнение только одной или сразу всех ожидаюн)их нитей при изменении значения выражения.
Использование условных переменных является более приемлемым, чем применение простых блокировок. 308 Глава 7. Синхронизация. Многопроцессорные системы Представьте ситуацию, в которой одна или несколько нитей серверного приложения находятся в ожидании запросов клиентов. Поступающие запросы передаются ожидающим их нитям. Если ни одна из нитей пе может в данный момент обработать поступивший запрос, то последний будет поставлен в очередь. Когда очередная нить серверного приложения заканчивает работу с одним запросом и становится готовой обрабатывать новый, то сначала она проверяет очередь.
Если в ней будет обнаружено сообщение, нить удалит его из очереди и начнет обработку запроса. Если очередь окажется пустой, нить приостанавливает выполнение в ожидании поступления нового запроса. Обра. ботка сообщений может быть реализована при помощи условных переменных, ассоциируемых с очередью запросов. В этом случае совместно используемыми данными является очередь сама по себе, а проверяемым условием — выражение «очередь не пуста». Механизм условных переменных схож с каналами спа, при использовании которых нити серверного приложения блокируются по условию и возобновляют работу после получения сообщений. На многопроцессорных системах необходимо зазцищать эти механизмы от состязательности, которая может привести к возникновению таких проблем, как потеря сигнала выхода из режима ожидания.