Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Операционные системы реального времени и технологии разработки кроссплатформенного программного обеспечения. Ч.1. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
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
в том, чтобы разработать такую модель поведения, которую можно выра­зить параллельным алгоритмом, чтобы ни один философ не голодал (т.е. чередовал прием пищи и размышления вечно).
Еще одной задачей является Спящий брадобрей.
Задача сформулирована при помощи гипотетической парикмахер­ской с одним парикмахером (брадобреем). У него есть всего одно рабочее место и приемная (очередь) со многими стульями. Когда он заканчивает подстригать очередного клиента, то ходит посмотреть в приемную, оста­лись ли клиенты. Если он видит клиентов, то приглашает только одного на рабочее место и стрижет. Если клиентов нет, парикмахер может отдохнуть, заняв свое рабочее место и заснуть. Если парикмахер храпит, то пришед­ший клиент будит его и садится в кресло. Если новый клиент видит, что парикмахер работает с клиентом, то он идет в приемную и ждет своей оче­реди. Если свободных стульев в приемной нет – клиент покидает очередь и идет по своим делам.
С первого взгляда кажется, что парикмахер стрижет любого пришед­шего клиента, пока есть сами клиенты, и спит, когда очередь пуста. С дру­гой стороны, могут появиться проблемы, связанные с фактом, что все дей­ствия и парикмахера, и клиента занимают неизвестное количество времени. Например, парикмахер может закончить стрижку и заснуть в то время, пока клиент идет в приемную, увидев ранее, что парикмахер занят. Или же па­рикмахер может проверить приемную, увидеть, что она пуста (потому, что ушедший туда ранее клиент, увидевший занятого парикмахера, еще не успел дойти и занять свое место для ожидания). Также возможна ситуация, что два клиента могут попытаться занять кресло парикмахера или свобод­ное кресло в приемной, увидев одновременно, что те пусты. И так далее.
Существует множество адекватных решений, но все они имеют одну общую черту: они должны использовать мьютекс, который гарантирует, что изменение состояния ресурса может выполнить только один из участ­ников процесса. Парикмахер должен перехватывать мьютекс, прежде чем он начнет проверять очередь, и освободить мьютекс перед тем, как он зай­мет место для отдыха или начнет работать с клиентом. С другой стороны, клиент должен захватить мьютекс перед тем, как войти в парикмахерскую, и должен освободить после того, как он займет место в приемной или ра­бочее место у парикмахера.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]