138
КОМПОНЕНТЫ И ТЕХНОЛОГИИ •
№ 8 '2011
компоненты
микроконтроллеры
Низкоприоритетная задача стала владель-
цем мьютекса ранее. Происходит некоторое
событие, за обработку которого отвечает вы-
сокоприоритетная задача. Она разблокиру-
ется и пытается захватить мьютекс (1), это
ей не удается, и она блокируется — момент
времени (2) на рис. 6. Однако в результате по-
пытки высокоприоритетной задачи захватить
мьютекс низкоприоритетная задача-владелец
мьютекса наследует приоритет этой высоко-
приоритетной задачи. Теперь низкоприори-
тетная задача не может быть вытеснена сред-
неприоритетной задачей. Поэтому в момент
времени (3), когда низкоприоритетная задача
завершила операции с ресурсом и возвращает
мьютекс, разблокируется, захватывает мью-
текс и начинает выполняться высокоприори-
тетная задача (4). Приоритет же низкоприори-
тетной задачи при этом возвращается к свое-
му «нормальному» значению.
Таким образом, механизм наследования
приоритетов уменьшает время реакции си-
стемы на событие, когда происходит инверсия
приоритетов (сравните величину dT на рис. 5
и рис. 6).
Продемонстрировать работу механизма на-
следования приоритетов во FreeRTOS позволяет
учебная программа № 2. В программе выпол-
няются две задачи: низкоприоритетная задача 1
с приоритетом 1 и высокоприоритетная задача 2
с приоритетом 2. Обе задачи пытаются захватить
один и тот же мьютекс. Низкоприоритетная за-
дача сигнализирует на дисплей, если ее приори-
тет изменился (повысился):
#include
#include
#include
#include “FreeRTOS.h”
#include “task.h”
#include “semphr.h”
/* Дескриптор мьютекса — глобальная переменная*/
volatile xSemaphoreHandle xMutex;
/* Низкоприоритетная задача 1. Приоритет = 1. */
static void prvTask1(void *pvParameters) {
long i;
/* Логическая переменная. Определяет, произошло ли
наследование приоритетов. */
unsigned portBASE_TYPE uxIsPriorityInherited = pdFALSE;
/* Бесконечный цикл */
for (;;) {
/* Наследования приоритетов еще не было */
uxIsPriorityInherited = pdFALSE;
/* Захватить мьютекс. */
xSemaphoreTake(xMutex, portMAX_DELAY);
/* Какие-то действия. За это время высокоприоритетная
задача попытается захватить мьютекс. */
for (i = 0; i < 100000L; i++)
;
/* Если приоритет этой задачи изменился (был унаследован
от задачи 2). */
if (uxTaskPriorityGet(NULL) != 1) {
printf(“Inherited priority = %d\n\r”, uxTaskPriorityGet(NULL));
uxIsPriorityInherited = pdTRUE;
}
/* Освободить мьютекс. */
xSemaphoreGive(xMutex);
/* Вывести значение приоритета ПОСЛЕ освобождения
мьютекса. */
if (uxIsPriorityInherited == pdTRUE) {
printf(“Priority after ‘giving’ the mutex = %d\n\r”,
uxTaskPriorityGet(NULL));
}
/* Блокировать задачу на промежуток времени случайной
длины: от 0 до 500 мс. */
vTaskDelay((rand() % 500));
}
}
/* Высокоприоритетная задача 2. Приоритет = 2. */
static void prvTask2(void *pvParameters) {
for (;;) {
xSemaphoreTake( xMutex, portMAX_DELAY );
xSemaphoreGive( xMutex );
/* Интервал блокировки короче — от 0 до 50 мс */
vTaskDelay((rand() % 50));
}
}
/*-----------------------------------------------------------*/
/* Точка входа. С функции main() начнется выполнение программы. */
short main( void )
{
/* Создание мьютекса. */
xMutex = xSemaphoreCreateMutex();
/* Создание задач, если мьютекс был успешно создан. */
if (xMutex != NULL) {
xTaskCreate(prvTask1, “prvTask1”, 1000, NULL, 1, NULL);
xTaskCreate(prvTask2, “prvTask2”, 1000, NULL, 2, NULL);
/* Запуск планировщика. */
vTaskStartScheduler();
}
return 1;
}
По результатам выполнения учебной про-
граммы № 2 (рис. 7) видно, что приоритет
задачи 1 временно увеличивается со значе-
ния 1 до значения 2, когда задача 2 пытается
захватить мьютекс, который уже захвачен за-
дачей 1. После того как задача 1 освобождает
мьютекс, ее приоритет возвращается к перво-
начальному значению.
Следует отметить, что механизм насле-
дования приоритетов во FreeRTOS только
уменьшает, однако не устраняет полно-
стью негативное влияние инверсии приори-
тетов. Поэтому рекомендуется проектиро-
вать программу так, чтобы избегать ситуа-
ции инверсии приоритетов.
Достарыңызбен бөлісу: