- •Системное программное обеспечение
- •Разд. 1. Операционные системы и среды
- •Тема 1.1. Структура программного обеспечения вычислительной системы
- •Тема 1.2 Назначение, функции и структура операционной системы
- •1.2.1 Типы ос. Системы реального времени и операционные системы реального времени
- •Тема 1.3. Управление временем центрального процессора
- •Рекомендуется всегда проверять возвращаемое значение Res. Получение и использование процессом ссылок на себя
- •Использование потоков при разработке приложений
- •1.3.3 Синхронизация взаимодействующих потоков
- •Interlocked – функции.
- •Семафорные примитивы Дейкстры
- •Решение проблемы критических участков с помощью семафорных примитивов Дейкстры
- •1.3.4 Синхронизации потоков средствами операционной системы
- •Пример 2
- •Пример 3 Поток_1 Поток_2
- •1.3.5. Проблема тупиков и методы борьбы с тупиками
- •Взаимного исключения, при котором процессы имеют монопольный доступ к ресурсам;
- •Ожидания, при котором процесс, запрашивающий ресурс, ждет до тех пор, пока запрос не будет удовлетворен, удерживая ранее полученные ресурсы;
- •Методы борьбы с тупиками
- •Тема 1.4 Управление памятью
- •Защищенный режим процессоров Intel и его возможности
- •1.4.2. Реализация многозадачного режима в защищенном режиме процессоров фирмы Intel
- •Аппаратная поддержка многозадачности
- •Обработка прерываний в реальном режиме. Вектора прерываний.
- •Режимы работы мп 386
- •Системный режим
- •Особенности s – режима.
- •Организация виртуальной памяти
- •Управление страничной памятью в ос ms Windows
- •Линейный адрес
- •1.4.4. Разделы в виртуальном адресном пространстве процесса
- •Области применения dll
- •Основные dll ms Windows:
- •Создание dll
- •Использование dll (импорт функций из dll)
- •Неявная загрузка dll (неявное подключение)
- •Явная загрузка dll
- •Выполнение процедур инициализации и деинициализации Dll
- •Тема 1.6 Структура ms Windows и драйверы режима ядра
- •Тема 1.7 Управление вводом-выводом и файловые системы Win32
- •Эволюция файловых систем эвм
- •Раздел 2. Программирование в операционной среде
- •Тема 2.1. Ассемблеры и макроязыки
- •2.1.1. Этапы подготовки программы к выполнению
- •Операнды команд
- •Алгоритмы работы Ассемблеров
- •Двухпроходный Ассемблер - 1-й проход
- •2.1.2. Макроязыки
- •Заголовок макроопределения
- •Окончание макроопределения
- •Локальные переменные макроопределения
- •Присваивание значений переменным макроопределения
- •Оператор безусловного перехода и метки макроопределения
- •Тема 2.2.Трансляторы
- •2.3.1. Трансляторы. Компиляторы и интерпретаторы. Мобильность программного обеспечения
- •Тема 2.3 Формальные языки и грамматики
- •Синтаксический и лексический анализатор
- •Детерминированные и недетерминированные автоматы
- •Алгоритм синтаксического анализа
- •Пример 1
- •Пример 2
Пример 2
В этом примере состояние объектов, указанных в функции WaitForSingleObject изменяется в момент вызова функции.
Поток_1
если
свободен ––> WaitForSingleObject(Handle_Mutex, infinite) (или событие с автоматическим сбросом )
m
utex
если не свободен – стоп.
При вызове функции WaitForSingleObject (…), если объект свободен, продолжает выполнение, а состояние объект изменится на противоположное (остальные процессы, в которых используется WaitForSingleObject() c этим Mutex будут ждать).
В случае функции WaitForMultipleObjects (когда 3-й параметр равен TRUE) – объекты указанные в массиве, переустанавливаются в занятое состояние до тех пор, пока не освобождаются все указанные объекты (сначала дождаться освобождения всех, затем устанавливать в занятое). Это сделано, чтобы избежать тупиков.
Это относится к функции WaitForMultipleObjects.
(если параметр равен TRUE), лишь одного объекта (если FALSE). Четвертый параметр – аналогичен последнему параметру предыдущей функции. Возвращаемое значение – индекс описателя в массиве описателей того объекта, который освободился (если освободилось несколько, то первого из освободившихся).
102Н – ни один из объектов в течение заданного времени не освободился.
Пример 3 Поток_1 Поток_2
ждать mutex A ждать mutex A,
и mutex B mutex B
Допустим, поток_3 освободил mutex A. Тогда ОС передает права на него потоку_1. Затем 3-й поток освободит mutex B.
Система передает права на него потоку_2.
Теперь поток_1 и поток_2 друг друга – 1-й владеет mutex’ом A, но не может выполнятся и освободить его, поток_2 никогда не освододит mutex A. Поток_2 – владеет B, но никогда не освободит его.
Это пример тупика двух процессов.
Для борьбы с тупиками функция WaitForMultipleObjects никогда не восстанавливает занятое состояние объектов, пока все из числа указанных объектов не освободятся.
Применение Обектов mutex вместо критических критических секций.
Вместо критических секции используется Mutex.
1) создать mutex
HM:=CreateMutex(nil, False, nil);
2) создать поток
Th1:=CreateTHread(nil, ….);
Th2:= CreateTHread(nil, …);
Перед критическим участком каждого потока вызвать функцию
WaitForSingleObject (HM, Infinite) (если HM свободен, он переводится в занятое состояние, а поток входит в критический участок). В конце критического участка необходимо перевести mutex в свободное состояние.
ReleaseMutex (Hmutex):boolean; Эта функция переводит объект mutex из занятого состояния в свободное (аналогично LeaveCriticalSection ).
Функция ReleaseMutex воздействует на mutex, только если поток, вызвавший ее, владеет этим объектом.
Отказ от объекта mutex
Объект mutex отличается от других синхронизирующих объектов ядра тем, что вызвавшему его потоку передаются права на владения им. Другие синхронизирующие объекты могут быть либо свободны, либо заняты. А объекты mutex способны еще и запомнить, какому потоку они принадлежат.
В случае аварийного завершения потока, владеющего объектом Mutex, Mutex никогда не освободить, так как никакой другой поток не сможет освободить его вызовом функции RealeseMutex. ОС не терпит подобных ситуаций и переводит mutex в свободное состояние (для предотвращения блокировки оставшихся потоков). Это действие называется отказ от мьютекса.
С объектами mutex связан счетчик числа их владельцев. Поэтому, если поток вызывает WaitForSingleObject для того объекта mutex, который уже принадлежит ему, он сразу получит доступ к защищенным данным (благодаря счетчику система определяет, что поток уже владеет объектом mutex). При каждом вызове WaitForSingleObject потоком – владельцем объекта mutex – этот счетчик увеличивается на 1. Поэтому для освобождения mutex потоку придется соответствующее число раз вызывать функцию RealeseMutex.
Семафоры
Объекты ядра “семафор” используются для учета ресурсов. При запросе у семафора ресурса ОС проверяет, свободен ли данный ресурс, и если свободен, уменьшает счетчик доступных ресурсов, не давая вмешиваться другому потоку. Только после этого система разрешает другому потоку запрашивать какой-либо ресурс. Например, у ПК установлено три последовательных порта, значит одновременно или могут воспользоваться не более чем три потока ( порт может быть закреплен за одним потоком). Для выделения портов необходимо создать семафор со счетчиком, равным 3. Семафор считается свободным, если его счетчик ресурсов больше 0, и занятым, если счетчик равен 0. При каждом вызове из потока функции WaitForSingleObject с передачей ей описателя семафора система проверяет, больше ли нуля счетчик ресурсов у данного семафора. Если да, то счетчик ресурсов уменьшается на 1, выполнение потока продолжается. Если счетчик ресурсов=0, поток должен ждать освобождения ресурса.
В отличие от mutex, семафоры не передаются во владение какому-либо потоку.
Семафор создается функцией
CreateSemafore (nil //атрибуты, InitSem, MaxSem //integer, LpszSemName // Имя семафора для ссылок на семафор из других процессов): Thandle;
Для случая использования 3 портов семафор создается функцией
Hs := CreateSemafore (nil, 3, 3, ‘’);
.– все 3 порты свободны.
Освобождение семафора – увеличение счетчика ресурсов – выполняет функция
ReleaseSemafore (HandleSem, CRelease //количество возвращаемых ресурсов, lpPrevios):boolean;
Последний параметр – указывает на переменную integer, в которую заносится значение счетчика ресурсов, предшествовавшему тому, что получается после увеличения его на CRelease. Можно передавать nil.
Получить содержимое счетчика семафора, не измерив его значения, нельзя.
Решение задачи поставщик – потребитель с помощью операций P(S) и V(S)
InitSem (Sсв, N)
InitSem (Sзап, 0)
InitSem (Sвз, 1)
Поставщик: WhileTrue do
Begin
Создать сообщение
P(Sсв)
P(Sвз)
Послать сообщение
V(Sсв)
V(Sвз)
End.
Потребитель: WhileTrue do
Begin
Создать сообщение
P(Sзап)
P(Sвз)
Послать сообщение
V(Sсв)
V(Sвз)
End.
Семафоры Sсв, Sзап используется как счетчики свободных и занятых буферов т.е. являются общими переменными для обоих потоков. Поэтому они должны быть защищены двоичным семафором Sвз. Если поставщик проверил P(Sсв) и находится на семафоре Sсв=0, он блокируется на нем. Если потребитель проверил P(Sзап) и находит при этом Sзап.=0, он блокируется на семафоре Sзап.
2 семафора предназначен для возможности блокировки 2 потоков. 3-й семафор Sвз обеспечивает неделимость операций.
.
События - Event.
Самые примитивные средства синхронизации – только оповещают об окончании какой-либо операции. Используются два типа объектов “события” :
событие со сбросом вручную (manual-reset-events);
событие с автоматическим сбросом (auto-reset-events).
Типичная схема использования событий – 1 поток выполняет некоторую подготовительную операцию (например, считывание данных из файла в буфер), а затем сигнализирует другому потоку (или нескольким потокам), что они могут продолжить работу (например, обработать считанные данные).
