- •Операционные системы (учебное пособие)
- •Введение
- •1. Операционная система: основные понятия
- •1.1. Понятие операционной системы, её роль и функции
- •1.2. Операционная и программная среды
- •1.3. Очередь и стек
- •1.4. Машинная команда, способы адресации, привилегированные команды
- •1.5.Система прерываний
- •1.6. Задачи, вычислительные процессы и ресурсы
- •Ресурс – это абстрактная структура, имеющая множество атрибутов, характеризующих способы доступа к ресурсу и его физическое представление в системе
- •1.7. Мультипрограммный, мультизадачный и многопользовательский режимы работы операционной системы. Режим разделения времени
- •2. Управление памятью в операционных системах
- •2.1. Память и отображения, виртуальное адресное пространство
- •2.2. Простое непрерывное распределение и распределение с перекрытием
- •2.3. Распределение памяти статическими разделами
- •2.4. Распределение памяти с динамическими разделами
- •2.5. Распределение памяти с фрагментацией задач
- •3. Управление процессами
- •3.1. Реализация последовательного процесса в операционной системе
- •3.2. Планирование и диспетчеризация процессов и задач
- •3.3. Управление параллельными процессами
- •3.3.1. Понятие параллельных процессов
- •3.3.2. Методы реализации взаимных исключений
- •3.3.3. Блокировка памяти
- •3.3.4. Применение специальных операций типа "проверка–установка"
- •3.3.5.Семафоры и их применение
- •3.3.6. Мониторы
- •3.3.7. Почтовые ящики, конвейеры и очереди сообщений
- •4. Проблема тупиков и её решение
- •4.1. Проблема тупиков, разделяемые ресурсы и модели параллельных процессов
- •4.2. Модель повторно используемых ресурсов Холта1
- •4.3. Сети Петри
- •4.4. Модель пространства состояний системы
- •4.5. Борьба с тупиками
- •4.5.1. Предотвращение тупиков
- •4.5.2. Обход тупиков
- •4.5.3. Обнаружение тупика
- •5. Жёсткий диск
- •5.1. Устройство накопителя жесткого диска (hdd) и адресация элементов дискового пространства
- •5.2. Логическая структура диска
- •5.3. Создание загрузочных дисков
- •6. Файловые системы
- •6.1. Файлы и каталоги
- •6.2. Понятие и функции файловой системы и системы управления файлами.
- •6.3. Обзор файловых систем
- •6.3.1. Файловая система fat16, fat32 и vfat
- •6.3.2. Файловая система ntfs
- •6.3.3. Файловые системы компакт-дисков
- •7. Средства защиты и восстановления операционных систем
- •7.1. Цифровая подпись драйверов и её верификация
- •7.2. Защита и проверка системных файлов
- •7.3. Откат драйверов
- •7.6. Безопасный режим загрузки
- •7.7. Мастер и точки восстановления системы
- •7.8. Резервное копирование и восстановление
- •7.9. Аварийное восстановление системы. Консоль восстановления.
- •8. Загрузчики операционных систем
- •8.1. Понятие загрузчика и виды его реализации
- •8.2. Решение проблемы четырех разделов в mbr
- •8.3. Установка загрузчиков ос
- •8.4. Настройка загрузчиков ос
- •8.5. Удаление загрузчиков ос
- •9. Системный реестр и системные службы
- •9.1. Назначение и структура реестра
- •9.2. Работа с реестром
- •9.3. Системные службы
- •10. Безопасность операционных систем
- •10.1. Угрозы, уязвимости, атаки
- •10.2. Политика безопасности
- •10.3. Защита от вторжений
- •10.4. Межсетевые экраны
- •10.5. Отключение ненужных служб
- •10.6. Защита от спама
- •10.7. Защита от вредоносных программ и вирусов средствами операционных систем
- •10.8. Защита конфиденциальной информации.
- •Список литературных источников
3.3.4. Применение специальных операций типа "проверка–установка"
Причиной возникновения проблем при реализации взаимного исключения посредством блокировки памяти является реализация механизма двумя командами "проверить флаг" и "становить флаг". Во время исполнения этой пары операций доступ к флагам имеют все процессы, конкурирующие за критический ресурс. Попытка решить эту проблему аппаратными средствами была сделана ещё в знаменитых машинах IBM 360 и IBM 370. В них появилась единая неделима команда TS (Test and Set) проверки и установки переменных. Т.к. эта команда неделима, то на время её использования одним процессом проверяемая переменная становится недоступна другим процессам.
Команда TS имеет формат:
TS (операнд_1, операнд_2).
В процессе её выполнения в операнд_1 копируется значение из операнд_2, а операнд_2 получает значение единица.
Для реализации взаимного исключения, как и в случае блокировки памяти, создаются два флага перекл_1 и перекл_2, а также переменная common. Все три переменные являются общими для конкурирующих за критический ресурс процессов. При запуске процессов Р1 и Р2 переменная common получает значение нуль. Перед вхождением в свои критические секции процессы Р1 и Р2 ставят свои флаги в состояние единица и выполняют команду TS:
процесс Р1: перекл_1:=1; TS(перекл_1,common);
процесс Р2: перекл_2:=1; TS(перекл_2,common).
В результате выполнения команды TS флаги получают значения переменной common, а переменная common – значение единица. После выполнения каждым процессом критической секции происходит установка переменной common в состояние нуль.
В архитектуре IA32 команда TS получила своё развитие, в результате которого появились три команды BTC, BTS и BTR.
Однако недостатком этого метода является большой расход процессорного времени на процессы, которые не выполняются, а ожидают права на вхождение в критические секции, т.к. они непрерывно проверяют значение переменной common. Таким образом, и применение специальной операции "проверка–установка" является недостаточно эффективным.
3.3.5.Семафоры и их применение
Одной из причин низкой эффективности рассмотренных в 2.3.3 и 2.3.4 методов реализации взаимных исключений является наличие двух и более переменных, анализируемых и устанавливаемых двумя раздельными или одной специальной командой. Более перспективным способом представляется использование для анализа возможности вхождения процесса в критическую секцию одной переменной и возможности запрета прерываний во время исполнения критической секции процесса.
Эта идея реализована в семафорных примитивах Дейкстры. Семафором называется переменная специального типа, которая доступна параллельным процессам. Для управления семафором S процессы могут использовать только две операции: "открыть" V(S) и "закрыть" P(S).
При старте процессов должна выполняться инициализация семафора, т.е. задание ему начального значения. Инициализация семафора осуществляется операцией InitSem(Имя_семафора, Начальное_состояние).
Семафор (S) является дополнительным критическим ресурсом, который указывается в качестве параметра операции, а операции P(S) и V(S) являются примитивами. Они неделимы и взаимно исключают друг друга.
Механизм семафора включается по запросу любого процесса из числа параллельных. Схема работы механизма семафора предусматривает проверку состояния ресурса, с которым связан семафор S, и в зависимости от состояния семафора допуск процесса к ресурсу или отказ в доступе к нему. При отказе в доступе процесс переводится в режим пассивного ожидания и, следовательно, не потребляет процессорное время. Разумеется, существует очередь ожидающих процессов. Средства обслуживания очереди входят в механизм семафорного процесса и реализуются супервизором операционной системы. Вследствие взаимного исключения примитивов P(S) и V(S) попытка одновременного выполнения примитивов несколькими разными процессами приведёт к тому, что только один из них успешно выполнит примитив, т.е. будет выполнено взаимное исключение процессов.
В настоящее время существует достаточно много семафорных механизмов, описанных в [5] и различающихся следующими параметрами:
начальное значение семафора;
диапазон допустимых значений семафора;
логика действий семафорных операций;
количество семафоров, доступных примитивам для обработки.
Различают семафоры с разным числом состояний. Существуют двоичные семафоры, имеющие два состояния: "открыт" и "закрыт". Такие семафоры называются мьютексами. Существуют семафоры, имеющие N состояний. Среди них различают семафоры столько положительными значениями и семафоры, допускающие отрицательные значения. В таких семафорах отрицательные значения указывают длину очереди процессов, ожидающих критический ресурс.
Два варианта реализации семафора показаны на рис. 3.4. В обоих случаях описания примитивов можно оформит в виде процедур или процедур-функций. Примитив P(S) вызывается процессом перед вхождением в критическую секцию. Примитив V(S) вызывается после выполнения критической секции.
В варианте рис. 3.4,а примитив P(S) сразу уменьшает значение семафора на единицу и, если новое значение семафора меньше нуля операцией WAIT(S) останавливает процесс и помещает его в очередь ожидания к семафору S. В варианте рис. 3.4,б сначала проверяется значение семафора и, если оно не меньше единицы, то значение семафора уменьшается на единицу. В противном случае операцией WAIT(S) процесс останавливается и помещается в очередь ожидания к семафору.
P(S): S:=S-1; If S<0 Then WAIT(S)
V(S): If S<0 Then RELEASE(S); S:=S+1
а)
P(S): If S>=1 Then S:=S-1 Else WAIT(S)
V(S): If S<0 Then RELEASE(S); S:=S+1
б)
Рис. 3.4. Неудачный (а) и удачный (б) варианты реализации примитивов P(S) и V(S)
Примитив V(S) в обоих вариантах проверяет значение семафора S и если оно меньше нуля, то операцией RELEASE(S) ставит один из ожидающих семафор процессов в очередь готовности. Перед завершением обработки семафора примитив увеличивает значение семафора на единицу.
Применение обоих вариантов реализации семафоров можно проиллюстрировать программным кодом, показанным на рис. 3.5.
-
Var S: Semafor
Begin
InitSem(S,1)
{описание переменной S типа Semafor}
{начало программного кода}
{инициализация семафора S значением единица}
Parbegin
{начало описания параллельных процессов}
while true do
{организация бесконечного процесса Р1 }
begin
P(S)
CS1
V(S)
end
{начало описания тела процесса Р1}
{вызов примитива P(S)}
{выполнение критической секции процесса Р1}
{вызов примитива V(S)}
{конец описания тела процесса Р1}
AND
{разделитель описаний процессов }
while true do
{организация бесконечного процесса Р2 }
begin
P(S)
CS1
V(S)
end
{начало описания тела процесса Р2}
{вызов примитива P(S)}
{выполнение критической секции процесса Р2}
{вызов примитива V(S)}
{конец описания тела процесса Р2}
Parend
{конец описания параллельных процессов}
End
{конец программного кода}
Рис. 3.5. Пример применения семафора
Один и тот же программный код (рис. 3.5) при использовании разных вариантов реализации семафора даст разный результат. Вариант реализации, показанный на рис. 3.4,б, будет надёжно работать, тогда как вариант рис. 3.4,а приведёт к ситуации, в которой заблокированы оба процесса (рис. 3.6.).
Рис. 3.6. Возникновение ситуации блокирования обоих процессов
Эта ситуация может возникнуть следующим образом. При запуске процессов Р1 и Р2 в семафор записана (+1). Оба процесса находятся в состоянии готовности. В момент времени t1 примитив P(S), вызванный процессом Р1 сбросит семафор в нуль. Во время выполнении критической секции CS1 процесса Р1 значение семафора равно нулю.
Однако в момент t2 примитив P(S), вызванный процессом Р2 запишет в семафор значение (-1), а сам процесс Р2 будет остановлен. В момент t3 примитив V(S) восстановит в семафоре значение ноль и переведет процесс Р2 в состояние готовности. Процесс Р1 останется в состоянии готовности.
Если Р2 попытается войти в свою критическую секцию, то это ему не удастся. В момент времени t4 в семафоре будет восстановлено значение (-1), процес Р2 будет остановлен и поставлен в очередь к семафору. Дальнейшая попытка процесса Р1 войти в свою критическую секцию будет также неудачна, процесс Р1 будет остановлен, и возникнет ситуация блокирования обоих процессов, из которой выхода нет.
Реализация неделимости примитивов P(S) и V(S) в однопроцессорной системе достигается простым отключением прерываний в критических секциях процессов и их последующим включением при выходе из неё. В многопроцессорных системах этот вариант не проходит, т.к. не запрещает одновременный запрос критического ресурса со стороны множества процессоров. Поэтому механизм семафоров несколько усложняется и дополняется аппаратной поддержкой взаимного исключения доступа для разных процессоров. Это может быть достигнуто, например, использованием неделимых команд "проверка – установка" TS, которые описаны в 3.3.4.
Некоторые особенности имеет применение двоичных семафоров (мьютексов). Они имеют два состояния "отмечен" (открыт) и "не отмечен" (закрыт). Мьютексы предназначены для организации взаимного исключения для потоков выполнения (задач) одного или нескольких процессов.
В любой момент времени мьютекс может принадлежать только одной задаче или не принадлежать ни одной из задач. Задача, захватившая мьютекс, снимает пометку и закрывает семафор. При освобождении мьютекса задача восстанавливает пометку, т.е. открывает семафор. Важнейшим свойством мьютекса является его имя, которое используется задачами для захвата в целях применения. При организации последовательного доступа к ресурсам с помощью мьютексов не возникает никаких затруднений. Для организации использования задачами разных процессов имя мьютекса должно передаваться по наследству" от одной задачи к другой.
Для работы с мьютексами используются системные вызовы (функции):
CreateMutex() – создание мьютекса;
OpenMutex() – открытие мьютекса;
WaitForSingleObject() – ожидание события от одного объекта;
WaitForMultipleObject() – ожидание события от множества объектов;
ReleaseMutex() – освобождение мьютексм.