Компоненты и технологии • №2 '2011 компоненты


FROM_ISR). Задачи-сторожа



Pdf көрінісі
бет91/129
Дата28.09.2023
өлшемі4.1 Mb.
#478975
1   ...   87   88   89   90   91   92   93   94   ...   129
Kurniz

FROM_ISR).
Задачи-сторожа
(Gatekeeper tasks)
Задачи-сторожа предоставляют простой 
и прозрачный метод реализации механизма 
взаимного исключения, которому не прису-
щи проблемы инверсии приоритетов и вза-
имной блокировки.
Задача-сторож — это задача, которая 
имеет единоличный доступ к разделяемо-
му ресурсу. Никакая другая задача в про-
грамме не имеет права обращаться к ре-
сурсу напрямую. Вместо этого все задачи, 
разделяющие общий ресурс, обращаются 
к задаче-сторожу, используя безопасные ме-
ханизмы межзадачного взаимодействия 
FreeRTOS. Непосредственно действия с ре-
сурсом выполняет задача-сторож.
В отличие от мьютексов, работать с кото-
рыми могут только задачи, к задаче-сторожу 
могут обращаться как задачи, так и обработ-
чики прерываний.
Рассмотрим использование задачи-
сторожа на примере учебной программы 
№ 3. Как и в учебной программе № 1, здесь 
разделяемым ресурсом выступает консоль. 
В программе созданы две задачи, каждая 
из которых выводит свое сообщение на кон-
соль. Кроме того, сообщения выводит функ-
ция, вызываемая каждый системный квант 
времени, это демонстрирует возможность 
обращения к разделяемому ресурсу из тела 
обработчика прерывания:
#include “FreeRTOS.h”
#include “task.h”
#include “semphr.h”
#include
#include
/* Прототип задачи, которая выводит сообщения на консоль, 
передавая их задаче-сторожу.
* Будет создано 2 экземпляра этой задачи */
static void prvPrintTask(void *pvParameters);
/* Прототип задачи-сторожа */
static void prvStdioGatekeeperTask(void *pvParameters);
/* Таблица строк, которые будут выводиться на консоль */
static char *pcStringsToPrint[] = {
“Task 1 ****************************************************\r\
n”,
“Task 2 ----------------------------------------------------\r\n”,
“Message printed from the tick hook interrupt ##############\r\n” 
};
/*-----------------------------------------------------------*/
/* Объявить очередь, которая будет использоваться для передачи 
сообщений от задач и прерываний к задаче-сторожу. */
xQueueHandle xPrintQueue;
int main(void) {
/* Создать очередь длиной макс. 5 элементов типа 
“указатель на строку” */
xPrintQueue = xQueueCreate(5, sizeof(char *));
/* Проверить, успешно ли создана очередь. */
if (xPrintQueue != NULL) {
/* Создать два экземпляра задачи, которые будут выводить 
строки на консоль, передавая их задаче-сторожу. 
В качестве параметра при создании задачи передается 
номер строки в таблице. Задачи создаются с разными 
приоритетами. */
xTaskCreate(prvPrintTask, “Print1”, 1000, (void *) 0, 1, NULL);
xTaskCreate(prvPrintTask, “Print2”, 1000, (void *) 1, 2, NULL);
/* Создать задачу-сторож. Только она будет иметь 
непосредственный доступ к консоли. */
xTaskCreate(prvStdioGatekeeperTask, “Gatekeeper”, 1000, NULL, 
0, NULL);
/* Запуск планировщика. */
vTaskStartScheduler();
}
return 0;
}
/*-----------------------------------------------------------*/
static void prvStdioGatekeeperTask(void *pvParameters) {
char *pcMessageToPrint;
/* Задача-сторож. Только она имеет прямой доступ к консоли.
* Когда другие задачи “хотят” вывести строку на консоль, 
они записывают указатель на нее в очередь.
* Указатель из очереди считывает задача-сторож 
и непосредственно выводит строку */
for (;;) {
/* Ждать появления сообщения в очереди. */
xQueueReceive(xPrintQueue, &pcMessageToPrint, portMAX_
DELAY);
/* Непосредственно вывести строку. */
printf(“%s”, pcMessageToPrint);
fflush(stdout);
/* Вернуться к ожиданию следующей строки. */
}
}
/*-----------------------------------------------------------*/
/* Задача, которая автоматически вызывается каждый системный 
квант времени.
* Макроопределение configUSE_TICK_HOOK должно быть равно 1. */
void vApplicationTickHook(void) {
static int iCount = 0;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* Выводить строку каждые 200 квантов времени. 
Строка не выводится напрямую, указатель на нее помещается 
в очередь и считывается задачей-сторожем. */
iCount++;
if (iCount >= 200) {
/* Используется API-функция, предназначенная для вызова 
из обработчиков прерываний!!! */
xQueueSendToFrontFromISR(xPrintQueue, &(pcStringsToPrint[2]),
&xHigherPriorityTaskWoken);
iCount = 0;
}
}
/*-----------------------------------------------------------*/
static void prvPrintTask(void *pvParameters) {
int iIndexToString;
/* Будет создано 2 экземпляра этой задачи. В качестве параметра 
при создании задачи выступает номер строки в таблице строк. */
iIndexToString = (int) pvParameters;
for (;;) {
/* Вывести строку на консоль. Но не напрямую, а передав 
указатель на строку задаче-сторожу.*/
xQueueSendToBack(xPrintQueue, &(pcStringsToPrint[iIndexT
oString]), 0);
/* Блокировать задачу на промежуток времени случайной 
длины: от 0 до 500 квантов. */
vTaskDelay((rand() % 500));
/* Вообще функция rand() не является реентерабельной.
Однако в этой программе это неважно. */
}
}


Достарыңызбен бөлісу:
1   ...   87   88   89   90   91   92   93   94   ...   129




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет