Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Операционные системы реального времени и технологии разработки кроссплатформенного программного обеспечения. Ч.1. Учебное пособие
.pdf
5.6. Мьютексы. Система событий
101
Это немаловажный аспект синхронизации, сопряженный с самим
форматом сообщений. В той или иной системе реального времени могут
использоваться сообщения либо с фиксированной длиной (и установленным заранее форматом) либо с динамической размерностью.
Во втором случае, длина сообщения фигурирует в нем в особой секции заголовка сообщения. Это число, занимающее обычно несколько байт
памяти, которое находится на строго определенном месте в заголовке. Сам
по себе заголовок сообщения состоит из множества служебных полей, но
обязательно выравнивается до позиции длины сообщения. Алгоритмы разбора и обработки сообщения “знают” место расположения параметра
длины сообщения, могут его прочитать и далее рассчитать фактическую
длину сообщения.
Именно по этому принципу, например, работают механизмы стандарта локальных и глобальных сетей типа Ethernet (где само сообщение
имеет нефиксированный размер, указываемый в параметре длины).
Обычно длину сообщения стараются ограничить. Это связано с заявляемыми при разработке системы объемами буфера для хранения и передачи сообщений. Иногда сообщение выравнивают по длине до значения,
являющегося степенью числа 2 (два).
5.6. Мьютексы. Система событий
Далее рассмотрим еще один способ синхронизации – синхронизация
на основе мьютексов.
Мьютексы похожи на критические разделы системы за исключением
того, чтоб при помощи мьютексов можно выполнять синхронный доступ к
ресурсам общего пользователя одновременно со стороны нескольких процессов. Точнее сказать со стороны потоков, составляющих разные процессы. Мьютекс имеет системный уровень, т.е. является объектом ядра операционной системы реального времени.
Мьютекс обладает эксклюзивным правом использования ресурса,
если поток, которому ресурс требуется, является владельцем этого мьютекса.
Другие потоки не могут завладеть мьютексом, который уже принадлежит другому потоку. Если мьютекс выполняет защиту каких-либо данных, которые используются совместно, то он сможет выполнить свою

5. Синхронизация и взаимодействие процессов
102
функцию только тогда, когда все потоки уже проверили состояние
мьютекса и у них есть соответствующий доступ.
Также существует еще один метод синхронизации задач – система
событий.
События обычно возникают в какой-либо ситуации либо вызыва-
ются напрямую. В любом случае, о событиях оповещаются все “заинтересованные” объекты в системе. События так же, как и мьютексы, являются
объектами ядра операционной системы реального времени.
Одиночное событие можно назвать скорее “флагом”, т.е. некоторым
признаком, например, окончания какого-либо процесса.
Событие находится в сигнальном состоянии, если оно было сформи-
ровано каким-либо потоком.
Единичное событие означает ситуацию, когда потоку нужно, чтобы
на его событие реагировал только один из существующих потоков, а другие
– просто ждали. После возникновения такого единичного события, все множество потоков будет находиться в состоянии ожидания, а этот определенный поток будет оповещен о возникновении события и сможет продолжать
работу. После окончания работы потока по данному событию, система автоматически сбросит флаг (удалит единичное событие из системы).
Есть разновидность событий: мануальное событие. Это не простой
флаг для нескольких потоков. Мануальное событие решает более сложную
проблему. Любой поток может установить или сбросить событие (выполнить его очистку). Если событие уже установлено, то оно останется в данном состоянии сколь угодное время. И это состояние не зависит от того,
сколько потоков находится в состоянии ожидания этого события. Когда все
ожидающие события потоки получат сообщение о возникновении этого события, событие автоматически сбрасывается.
5.7. Объекты синхронизации POSIX
Стандарт POSIX уже рассматривался ранее в общих чертах. В данном разделе будет дано определение части этого стандарта, касающейся
объектов синхронизации, которые должны присутствовать в системе “реального времени”.

5.7. Объекты синхронизации POSIX
103
POSIX описывает ряд понятий, которые приводились выше, а также
дает больше деталей и конкретных данных.
Для начала следует упомянуть, что POSIX подробно раскрывает та-
кие объекты синхронизации, как мьютексы, представляя их как развитие
бинарных (булевых) семафоров, и давая рекомендации в плане повышения
быстродействия и безопасности работы программ с мьютексами. Типичным циклом работы программы, согласно стандарту, является следующая
последовательность действий:
1. необходимо взять семафор для ресурса;
2. поработать с ресурсом;
3. если во время работы программы возникли ошибки, то необхо-
димо сразу вернуть семафор (не забирая его на себя) и выполнить цикл
работы с начала с разделяемым ресурсов, не блокируя последний, если
ресурс занят;
4. вернуть семафор, если программа нормально завершилась.
При выполнении алгоритма, процесс решения задачи сопровожда-
ется работой с объектом типа мьютекс, который состоит из комбинации бинарного семафора и идентификатора задачи. Идентификатор задачи – это
метка текущего владельца семафора, т.е. той самой задачи, которая
успешно осуществила вызов функции взятия семафора и стала владельцем
разделяемого ресурса.
Для доступа к специальному объекту типа мьютекс, стандарт опре-
деляет три примитивные операции:
блокировка мьютекса (Lock);
разблокировка мьютекса (Unblock);
попытка блокировки мьютекса (Try Block).
Все эти операции проводятся с определенным мьютексом М. Если
мьютекс М уже заблокирован какой-либо задачей, то данная задача переводит последнюю в состояние ожидания Разблокировки мьютекса. Если
мьютекс М ожидается какой-либо задачей T, то задача T может быть запущена, удалена из очереди ожидания и может вытеснить текущую задачу Tc.
Если задача, которая вызвала эту операцию, не является владельцем, то
операция не может быть завершена и не имеет никакого смысла. Если

5. Синхронизация и взаимодействие процессов
104
мьютекс М не блокирован, то операция Попытки блокирования эквивалентна операции Блокирования. Иначе, попытка возвращает флаг неудачного исполнения.
Данные операции являются атомарными, т.е. неделимыми. Переключение задач во время их выполнения запрещено.
Далее, стандарт определяет объекты синхронизации типа CondVar.
CondVar – это объекты специального типа, которые дают задаче T
возможность ожидания выполнения определенных условий Conditions – С.
Фактически, CondVar состоит как объект из комбинации объекта – события
Е с одним отличием: если от функции Отправки Send поступает какое-либо
событие, то активизируется только одна из очередей ожидающих событий.
Остальные очереди находятся в пассивном состоянии. Для CondVar определены три примитивные операции для доступа к объекту – событию E:
ожидание (Wait). Зависит от события E и мьютекса М;
сигнал (Signal). Зависит от события E;
рассылка (Broadcast). Зависит от события Е.
Ожидание сопряжено с выполнением трех операций, две из которых
являются атомарными, т.е. неделимыми:
вызов Разблокировки Unlock мьютекса М для текущей задачи;
вызов Ожидания Wait события Е;
вызов Блокировки Lock мьютекса М.
Рассылка Broadcast вызывает отправку Send события E и активизирует все ожидающие задачи так же, как это делает обычная операция Отправки Send.
Также POSIX описывает следующие типовые модели синхронизации.
5.8. Модели синхронизации POSIX
Поставщики-потребители
Данная модель синхронизации известна как Задача ограниченного
буфера (Bounded-buffer). Поставщик здесь носит название Producer, а потребитель – Consumer. Такая модель часто сейчас применяется при организации распределенных шин обмена данными в сложных проектах, в системах обмена сообщениями, а также в некоторых шаблонах проектирования.

5.8. Модели синхронизации POSIX
105
В оригинальном стандарте, задача описывает два процесса (соответственно процесс Поставщик и процесс Потребитель), которые вместе используют некоторый буфер для работы. Для буфера определены границы
или пределы. Задачей Поставщика является создание и запись в буфер
фрагмента данных, а при необходимости повторение этих действий раз за
разом, пока данные не дойдут до Потребителя.
Параллельно с этим, Потребитель читает (потребляет) данные, которые отправляет ему один или несколько Поставщиков, удаляя их из очереди.
Проблема состоит в том, чтобы не дать Поставщику записать данные
при полном буфере и не дать Потребителю удалить несуществующие данные при пустом буфере.
Передача всей информации осуществляется посредством буфера.
Этот буфер считается критическим ресурсом, для которого запрещены следующие действия:
одновременный доступ к буферу со стороны разных задач;
попытка чтения данных из пустого буфера;
попытка записи в заполненный до конца буфер.
Конечно, частичным решением такой проблемы может быть блокировка буфера на запись, если он полон, и блокировка для чтения, если он
пуст. Вместо блокировки по записи может быть использована модель или
сценарий “медленного потребителя”, в которой данные приходят как бы с
задержкой.
Когда Потребитель хочет удалить данные из буфера, он сообщает об
этом Поставщику и если тот считает, что удалять еще рано, снова записывает данные – начинает заполнять буфер снова.
Таким же точно образом, потребитель может перевести себя в режим
ожидания, если буфер оказывается пустым на момент возникновения необходимости чтения. Как только Поставщик запишет свои данные в пустой буфер, Потребитель узнает об этом из специального сигнала, так как Поставщик обязательно оповещает Потребителей о своих действиях с буфером.
Другим решением проблемы является взаимодействие между Поставщиком и Потребителем при помощи семафоров. Однако здесь ошибка
в реализации может привести к их взаимной блокировке. То есть оба процесса будут взаимно введены в режим Ожидания друг друга, как это показано на рис. 9.

5. Синхронизация и взаимодействие процессов
106
Рис. 9. Алгоритм с флагом блокировки
Следует учитывать, что разные задачи выполняются с разной скоро-
стью, им требуется разное время для выполнения.
С учетом этого, стандарт предлагает следующее решение озвучен-
ной проблемы – это алгоритм Деккера-Холта (рис. 10).
Как следует из его формального описания, алгоритм является гро-
моздким в реализации и несколько сложным во внедрении. Это особенно
заметно при решении проблемы синхронизации с большим количеством
задач, между которыми есть конкуренция.
Пожалуй, лучшее решение в стандарте POSIX описано как алгоритм
с использованием семафора Дейкстры.
Семафор Дейкстры – это некоторая целочисленная переменная S, с
которой связана очередь ожидающих задач и над которой разрешено проведение двух неразрывных (непрерываемых атомарных) операций.
Принцип работы алгоритма может быть описан следующим обра-
зом.
1. Выполнение операции Блокировки (ограждения):
S = S – 1;

5.8. Модели синхронизации POSIX
107
если S > 0, то текущая задача продолжает работу;
если S < 0 или S = 0, то задача перемещается в конец очереди
ожидания.
Рис. 10. Алгоритм Деккера-Холта
2. Выполнение операции Разблокировки (освобождения):
если S < 0 или S = 0, то в ход пускается первая задача в очереди;
S = S + 1;
первая в очереди задача продолжает работать.
Для блокировки одновременного доступа, достаточно использования всего одного семафора S1.
В этом случае выполнение алгоритма напоминает простое выполнение программного кода, когда Ограждение напоминает открывающую

5. Синхронизация и взаимодействие процессов
108
скобку блока кода, а операция Освобождения – последнюю скобку. Единственное, что следует здесь понимать, – работа ведется фактически до и
после критической секции.
Для того чтобы сделать невозможным чтение из пустого буфера и
невозможность записи в заполненный буфер, применяется еще два семафора: S2 и S3.
Пример алгоритма показан на рис. 11.
Рис. 11. Пример решения задачи Поставщик-потребитель
с применением семафоров
Существует еще один вариант решения описанной задачи, кроме
схемы Поставщик–Потребитель. Он называется Читатель–Писатель.
Данный метод решает задачу, когда несколько потоков пытаются по-
лучить доступ к одному общему ресурсу в одно и то же время.
1. Первая задача о Читателе–Писателе с приоритетом Читателя.
Здесь читателю или нескольким читателям дается свободный доступ к ресурсу, если он открыт на чтение. То есть Читатель беспрепятственно получает доступ к ресурсу, если нет ни одного Писателя. Это решение отдает

5.8. Модели синхронизации POSIX
109
предпочтение многим Читателям и ограничивает Писателей. Большой запрос на чтение от многих Читателей приводит фактически к блокировке
Писателей, так как последние никогда не получат доступ к занятому ресурсу (начинается состояние Голодания, Starvtion). Все читатели имеют доступ к устаревшей, не обновляемой информации.
2. Вторая задача о Читателе–Писателе с приоритетом Писателя. Как
только к ресурсу обращается хотя бы Писатель, все Читатели блокируются.
Ни один Читатель не входит в критическую секцию, так как он может нарушить неразрывность операции записи. В этом случае наблюдается состояние Голодания Читателей.
3. Третья задача о Читателе–Писателе с частным распределением
ресурсов. В данной ситуации стараются просто не допустить состояние
простоев ресурса. Говоря другими словами, вне зависимости от действий
потоков другого типа, Читатель и Писатель должны проходить свой барьер
за конечное время. Эти оба типа агентов имеют одинаковое значение приоритета, и для регулировки доступа применяется мьютекс.
Развитием задачи Читателей–Писателей является задача Обедающих философов. Она была предложена как пример в Информатике для описания проблем синхронизации при разработке параллельных алгоритмов и
решений. Впервые сформулирована Дейкстроем в 1965 г. как упражнение
для студентов в университете. Учитывая развитие вычислительной техники в то время, в качестве примера брался конкурирующий доступ к ленточному накопителю.
Проблема была далее оформлена и переформулирована Ричардом
Хоаром, и в таком виде остается и по сей день.
“Пять безмолвных философов сидят вокруг круглого стола. Перед
каждым стоит тарелка макарон. Вилки стоят на столе между каждой парой
ближайших философов. Каждый философ может либо есть, либо размышлять. Прием пищи не ограничен ни по времени, ни по объему (ресурс бесконечен). Тем не менее каждый философ может есть только тогда, когда
держит сразу две вилки: слева от себя и справа от себя. Каждый философ
может взять вилку, если она лежит на столе и положить, если он уже держит ее. Взятие каждой вилки и ее возвращение на стол – это две разные
операции, выполняемые строго последовательно”. Суть проблемы состоит

5. Синхронизация и взаимодействие процессов
110
в том, чтобы разработать такую модель поведения, которую можно выразить параллельным алгоритмом, чтобы ни один философ не голодал
(т.е. чередовал прием пищи и размышления вечно).
Еще одной задачей является Спящий брадобрей.
Задача сформулирована при помощи гипотетической парикмахерской с одним парикмахером (брадобреем). У него есть всего одно рабочее
место и приемная (очередь) со многими стульями. Когда он заканчивает
подстригать очередного клиента, то ходит посмотреть в приемную, остались ли клиенты. Если он видит клиентов, то приглашает только одного на
рабочее место и стрижет. Если клиентов нет, парикмахер может отдохнуть,
заняв свое рабочее место и заснуть. Если парикмахер храпит, то пришедший клиент будит его и садится в кресло. Если новый клиент видит, что
парикмахер работает с клиентом, то он идет в приемную и ждет своей очереди. Если свободных стульев в приемной нет – клиент покидает очередь и
идет по своим делам.
С первого взгляда кажется, что парикмахер стрижет любого пришедшего клиента, пока есть сами клиенты, и спит, когда очередь пуста. С другой стороны, могут появиться проблемы, связанные с фактом, что все действия и парикмахера, и клиента занимают неизвестное количество времени.
Например, парикмахер может закончить стрижку и заснуть в то время, пока
клиент идет в приемную, увидев ранее, что парикмахер занят. Или же парикмахер может проверить приемную, увидеть, что она пуста (потому, что
ушедший туда ранее клиент, увидевший занятого парикмахера, еще не
успел дойти и занять свое место для ожидания). Также возможна ситуация,
что два клиента могут попытаться занять кресло парикмахера или свободное кресло в приемной, увидев одновременно, что те пусты. И так далее.
Существует множество адекватных решений, но все они имеют одну
общую черту: они должны использовать мьютекс, который гарантирует,
что изменение состояния ресурса может выполнить только один из участников процесса. Парикмахер должен перехватывать мьютекс, прежде чем
он начнет проверять очередь, и освободить мьютекс перед тем, как он займет место для отдыха или начнет работать с клиентом. С другой стороны,
клиент должен захватить мьютекс перед тем, как войти в парикмахерскую,
и должен освободить после того, как он займет место в приемной или рабочее место у парикмахера.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
