Queues в Nucleus SE: Введение и основные Service Calls
View the RTOS Revealed series
Queues были введены в предыдущей статье. Они предоставляют более гибкий способ передачи простых сообщений между задачами, чем mailboxes.
Использование Queues
В Nucleus SE queues конфигурируются на этапе сборки. Максимум 16 queues может быть определено для приложения. Если queues не сконфигурированы, RTOS опускает все queue-связанные структуры данных и API код, держа бинарник lean.
Queue — просто массив слотов хранения, каждый достаточно большой для удержания одного ADDR data item. Доступ синхронизирован так, что множественные задачи могут безопасно enqueue и dequeue сообщения. Задачи могут писать в queue до заполнения всех слотов, и читать из queue в first-in, first-out (FIFO) порядке. Попытки отправить в полную queue или получить из пустой триггерят ошибку или приостановку задачи, в зависимости от выбранных API опций и конфигурации Nucleus SE.
Queues против Pipes
Nucleus SE также поддерживает pipes, которые отличаются в основном размером сообщения. Пока queue передает единичный ADDR (обычно указатель), pipe несет переменной-длины блок байтов; размер блока фиксируется на этапе конфигурации. Pipes будут обсуждены в глубине в будущей статье.
Конфигурация Queues
Количество Queues
Queue конфигурация контролируется #define директивами в nuse_config.h. Ключевая настройка — NUSE_QUEUE_NUMBER, определяющая, сколько queues включено. Дефолт 0 (нет queues). Вы можете установить любое значение от 0 до 16; out-of-range значение триггерит compile-time #error, производимый nuse_config_check.h.
Установка NUSE_QUEUE_NUMBER в ненулевое значение активирует queue подсистему, аллоцируя необходимые структуры данных и включая ассоциированные API вызовы.
API Enables
У каждой queue API функции есть enabling #define символ в nuse_config.h:
NUSE_QUEUE_SEND NUSE_QUEUE_RECEIVE NUSE_QUEUE_JAM NUSE_QUEUE_RESET NUSE_QUEUE_INFORMATION NUSE_QUEUE_COUNT
По умолчанию все установлены в FALSE, отключая соответствующие service calls. Для использования конкретного API установите его символ в TRUE. Включение API пока queues не сконфигурированы (кроме NUSE_Queue_Count(), который всегда разрешен) приводит к compile-time ошибке. Если API вызывается в коде, который не был включен, происходит link-time ошибка, потому что реализация опущена.
#define NUSE_QUEUE_NUMBER 0 /* Number of queues in the system – 0‑16 */ /* Service call enablers */ #define NUSE_QUEUE_SEND FALSE #define NUSE_QUEUE_RECEIVE FALSE #define NUSE_QUEUE_JAM FALSE #define NUSE_QUEUE_RESET FALSE #define NUSE_QUEUE_INFORMATION FALSE #define NUSE_QUEUE_COUNT FALSE
Queue Service Calls
Nucleus RTOS предлагает десять queue-связанных service calls, из которых шесть реализованы в Nucleus SE. Они предоставляют следующую функциональность:
- Отправить сообщение – NUSE_Queue_Send()
- Получить сообщение – NUSE_Queue_Receive()
- Jam сообщение в фронт – NUSE_Queue_Jam()
- Сбросить queue – NUSE_Queue_Reset()
- Запросить queue информацию – NUSE_Queue_Information()
- Получить число сконфигурированных queues – NUSE_Queue_Count()
- Оставшиеся вызовы (create, delete, enumerate, broadcast) недоступны в Nucleus SE.
Реализация каждого API обсуждается детально в следующих секциях.
Writing и Reading Services
Основные операции на queue — writing (sending) и reading (receiving). Writing в фронт queue называется jamming. Nucleus RTOS и Nucleus SE каждый экспонируют три базовых API вызова для этих действий.
Writing в Queue
RTOS API NU_Send_To_Queue() высоко гибок, позволяя неопределенную приостановку или таймаут если queue полна. Nucleus SE предлагает ту же функцию но приостановка опциональна и таймауты не поддерживаются. RTOS также поддерживает broadcast операцию, недоступную в SE.
RTOS API: NU_Send_To_Queue()
Прототип:
STATUS NU_Send_To_Queue(NU_QUEUE *queue, VOID *message, UNSIGNED size, UNSIGNED suspend);
Параметры:
- queue — указатель на user-supplied queue control block
- message — указатель на данные для отправки
- size — число UNSIGNED элементов; должно соответствовать message size очереди
- suspend — NU_NO_SUSPEND, NU_SUSPEND или значение таймаута
Коды возврата включают NU_SUCCESS, NU_QUEUE_FULL, NU_TIMEOUT и различные коды ошибок для невалидных указателей или состояния очереди.
SE API: NUSE_Queue_Send()
Прототип:
STATUS NUSE_Queue_Send(NUSE_QUEUE queue, ADDR *message, U8 suspend);
Параметры:
- queue — queue index (ID)
- message — указатель на ADDR значение для enqueue
- suspend — NUSE_NO_SUSPEND или NUSE_SUSPEND
Возвращаемые значения зеркалят RTOS функцию но отражают ограниченное blocking поведение SE.
Implementation Overview
Когда блокировка отключена, рутина просто проверяет наличие места и либо пишет значение, либо возвращает NUSE_QUEUE_FULL. С включенной блокировкой функция циклится, приостанавливая задачу если queue полна до появления места или возникновения reset. Реализация использует NUSE_Queue_Blocking_Count для отслеживания заблокированных задач и NUSE_Task_Blocking_Return для их возобновления когда слот открывается.
if (NUSE_Queue_Items[queue] == NUSE_Queue_Size[queue]) { return_value = NUSE_QUEUE_FULL; } else { NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] = *message; if (NUSE_Queue_Head[queue] == NUSE_Queue_Size[queue]) NUSE_Queue_Head[queue] = 0; NUSE_Queue_Items[queue]++; return_value = NUSE_SUCCESS; }
do { if (NUSE_Queue_Items[queue] == NUSE_Queue_Size[queue]) { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_QUEUE_FULL; } else { NUSE_Queue_Blocking_Count[queue]++; NUSE_Suspend_Task(NUSE_Task_Active, (queue << 4) | NUSE_QUEUE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) suspend = NUSE_NO_SUSPEND; } } else { NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] = *message; if (NUSE_Queue_Head[queue] == NUSE_Queue_Size[queue]) NUSE_Queue_Head[queue] = 0; NUSE_Queue_Items[queue]++; if (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; NUSE_Queue_Blocking_Count[queue]--; for (index = 0; index < NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } } while (suspend == NUSE_SUSPEND);
Цикл продолжается до успешного enqueue сообщения или разблокировки задачи resetом. Реализация обеспечивает thread-safe доступ и эффективное пробуждение заблокированных consumers.
Встроенный
- Камерные замки (Cam Locks): как они скрыто запирают шкафы
- Что такое кольцевые винты (Eye Screws)? Профессиональное руководство по дизайну и применению
- Громметы: виды, применение и защита вашего оборудования
- Нержавеющая сталь: состав, производство и глобальное влияние
- Основы ввода-вывода в C#: Console.WriteLine, ReadLine и форматирование
- Mailboxes в Nucleus SE: Практическое руководство по конфигурации и использованию
- Семафоры в Nucleus RTOS: Утилитарные сервисы и структуры данных
- Семафоры в Nucleus SE: Обзор, конфигурация и основы API
- Мастерство Event Flag Groups: Утилитарные сервисы и структуры данных в Nucleus RTOS/SE
- Event Flag Groups в Nucleus SE: Вводное руководство по конфигурации и использованию API