137
КОМПОНЕНТЫ И ТЕХНОЛОГИИ •
№ 8 '2011
www.kite.ru
компоненты
микроконтроллеры
Для того чтобы использовать рекурсивные мьютексы в про-
грамме, необходимо установить макроопределение
configUSE_
RECURSIVE_MUTEXES в файле
FreeRTOSConfig.h равным «1».
Как и обращение к обычному мьютексу, обращение к рекурсивно-
му мьютексу осуществляется с помощью дескриптора (идентифика-
тора) мьютекса —
переменной типа xSemaphoreHandle.
API-функции для работы с рекурсивными мьютексами:
xSemaphoreCreateRecursiveMutex()
•
— создание рекурсивного мью-
текса;
xSemaphoreTakeRecursive()
•
—
захват рекурсивного мьютекса;
xSemaphoreGiveRecursive()
•
— освобождение (возврат) рекурсив-
ного мьютекса.
Набор параметров и возвращаемое значение этих API-функций
ничем не отличаются от соответствующих API-функций для рабо-
ты с обычными мьютексами. Стоит помнить лишь о том, что API-
функции для работы с рекурсивными мьютексами нельзя применять
к обычным мьютексам и наоборот.
Проблемы при использовании мьютексов
Инверсия приоритетов
Вернемся к рассмотрению учебной программы № 1. Возможная
последовательность выполнения задач приведена на рис. 4. Такая
последовательность имела бы место, если во FreeRTOS не был бы
реализован механизм наследования приоритетов, о котором будет
рассказано ниже.
Пусть в момент времени (1) низкоприоритетная задача 1 вытес-
нила задачу Бездействие, так как закончился период пребывания
задачи 1 в блокированном состоянии (рис. 4). Задача 1 захватывает
мьютекс (становится его владельцем) и начинает посимвольно вы-
водить свою строку на дисплей (2). В момент времени (3) разбло-
кируется высокоприоритетная задача 2, при этом она вытесняет
задачу 1, когда та еще не закончила вывод строки на дисплей. Задача
2 пытается захватить мьютекс, однако он уже захвачен задачей 1,
поэтому задача 2 блокируется в ожидании, когда мьютекс станет
доступен. Управление снова получает задача 1, она завершает вы-
вод строки на дисплей — операция с ресурсом завершена. Задача
1 возвращает мьютекс обратно — мьютекс становится доступен
(момент времени (4)). Как только мьютекс становится доступен,
разблокируется задача 2, которая ожидала его освобождения. Задача
2 захватывает мьютекс (становится его владельцем) и выводит свою
строку на дисплей. Приоритет задачи 2 выше, чем у задачи 1, поэто-
му задача 2 выполняется все время, пока полностью не выведет
свою строку на дисплей, после чего она отдает мьютекс обратно
и блокируется на заданное API-функцией vTaskDelay() время — мо-
мент времени (5). Задача 1 снова получает управление, но на непро-
должительное время — пока также не перейдет в блокированное
состояние, вызвав vTaskDelay().
Учебная программа № 1 и рис. 4 демонстрируют одну из возмож-
ных проблем, возникающих при использовании мьютексов для реа-
лизации механизма взаимного исключения, — проблему инверсии
приоритетов (Priority Inversion) [7]. На рис. 4 представлена ситуация,
когда высокоприоритетная задача 2 вынуждена ожидать, пока низ-
коприоритетная задача 1 завершит действия с ресурсом и возвратит
мьютекс обратно. То есть на некоторое время фактический приори-
тет задачи 2 оказывается ниже приоритета задачи 1: происходит ин-
версия приоритетов.
В реальных программах инверсия приоритетов может оказывать
еще более негативное влияние на выполнение высокоприоритетных
задач. Рассмотрим пример. В программе могут существовать также
задачи со «средним» приоритетом — ниже, чем у высокоприоритет-
ной, которая ожидает освобождения мьютекса, но выше, чем у низ-
коприоритетной, которая в данный момент захватила мьютекс и вы-
полняет действия с разделяемым ресурсом. Среднеприоритетные
задачи могут разблокироваться на протяжении интервала, когда низ-
коприоритетная задача владеет мьютексом. Такой сценарий является
наихудшим, так как ко времени, когда высокоприоритетная задача
ожидает освобождения мьютекса, будет добавлено время выполне-
ния среднеприоритетных задач (рис. 5).
Низкоприоритетная задача стала владельцем мьютекса ранее.
Происходит некоторое событие, за обработку которого отвечает высо-
коприоритетная задача. Она разблокируется и пытается захватить мью-
текс (1), это ей не удается, и она блокируется — момент времени (2)
на рис. 5. Управление снова возвращается низкоприоритетной задаче,
которая в момент времени (3) вытесняется задачей, приоритет кото-
рой выше (среднеприоритетной задачей). Среднеприоритетная задача
может выполняться продолжительное время, в течение которого вы-
сокоприоритетная будет ожидать, пока мьютекс не будет освобожден
низкоприоритетной задачей (4). Время реакции на событие при этом
значительно удлиняется — величина dT на рис. 5.
В итоге инверсия приоритетов может значительно ухудшить время
реакции микроконтроллерной системы на внешние события.
Для уменьшения (но не полного исключения) негативного влияния
инверсии приоритетов во FreeRTOS реализован механизм наследова-
ния приоритетов (Priority Inheritance). Его работа заключается во вре-
менном увеличении приоритета низкоприоритетной задачи-владельца
мьютекса до уровня приоритета высокоприоритетной задачи, которая
в данный момент пытается захватить мьютекс. Когда низкоприори-
тетная задача освобождает мьютекс, ее приоритет уменьшается до зна-
чения, которое было до повышения. Говорят, что низкоприоритетная
задача наследует приоритет высокоприоритетной задачи.
Рассмотрим работу механизма наследования приоритетов на примере
программы
с высоко-, средне- и низкоприоритетной задачами (рис. 6).
Достарыңызбен бөлісу: