Перевод может содержать ошибки. Читайте первоисточник: Blocking on Multiple RTOS Objects
Назад: [Более подробно...] | Вверх: [Более подробно...] | Вперёд: [Более подробно...] |
Набор очередей - это возможность FreeRTOS, которая позволяет задаче ОС находиться в заблокированном состоянии, ожидая готовности нескольких очередей и/или семафоров одновременно. Очереди и семафоры группируются в наборы, тогда, вместо отдельных блокировок на каждой очереди и каждом семафоре, задача блокируется на наборе очередей.
Замечание: хотя иногда возникает необходимость блокировки на более чем одной очереди, если вы интегрируете FreeRTOS с устаревшим кодом сторонних разработчиков, проекты, которые свободны от таких ограничений, могут обычно достигать той же функциональности более эффективным способом, используя альтернативный шаблон проектирования, задокументированный внизу этой страницы. - дословно перевёл, а смысл до конца не понял.
Наборы очередей используются способом, похожим на использование функции API select() и связанных с ней функций, которые являются частью стандартного API сокетов Беркли.
Наборы очередей могут содержать очереди и семафоры, которые вместе называются членами наборов очередей. Параметры функций API и возвращаемые значения, которые могут принимать либо хэндл очереди, либо хэндл семафора, используют тип QueueSetMemberHandle_t. Переменные, имеющие тип QueueHandle_t и SemaphoreHandle_t обычно могут неявно преобразовываться в параметр, имеющий тип QueueSetMemberHandle_t. Аналогично может преобразовываться возвращаемое значение. При этом компилятор не будет выдавать предупреждений, т.е. явное преобразование к типу QueueSetMemberHandle_t и обратно не требуется.
Перед тем, как набор очередей можно будет использовать, его необходимо создать, используя вызов функции API xQueueCreateSet(). После создания на набор очередей можно ссылаться переменной типа QueueSetHandle_t.
Для добавления очереди или семафора к набору очередей используется функция API xQueueAddToSet().
Функция API xQueueSelectFromSet() используется для проверки готовности к чтению любого элемента набора очередей, - где "чтение" означает либо "получение" в случае очереди, либо "забирание" в случае семафора.
Как и при использовании функций API xQueueReceive() и xSemaphoreTake(), xQueueSelectFromSet() позволяет вызывающей задаче дополнительно блокироваться, пока член набора очередей не будет готов к чтению.
Значение NULL будет возвращено функцией xQueueSelectFromSet() в случае таймаута. В противном случае xQueueSelectFromSet() вернёт хэндл члена набора очередей, который готов к чтению, позволяя вызывающей задаче немедленно вызвать xQueueReceive() или xSemaphoreTake() (для хэндла очереди или хэндла семафора соответственно) с гарантией успешного завершения операции.
Страница с описанием функции API xQueueCreateSet() содержит пример исходного кода.
Стандартный демонстрационный файл QueueSet.c, расположенный в каталоге FreeRTOS/Demo/Common/Minimal из архива поставки FreeRTOS, содержит исчерпывающий пример.
Если нет каких-либо специфических проблем интеграции, которые требуют блокировки на нескольких очередях, похожий функционал обычно может быть достигнут с меньшим размером кода, меньшим объёмом ОЗУ и меньшими накладными расходами временеми выполнения, используя одну очередь. Реализация FreeRTOS+UDP предоставляет хороший пример того, как это можно сделать, и описана в следующей секции.
Задача, которая контролирует стек FreeRTOS+UDP, управляется событиями. Имеется много источников событий. Некоторые события не имеют никаких дополнительных данных. С некоторыми событими связаны дополнительные данные произвольной (неизвестной заранее) длины. События могут быть:
Стек UDP/IP could использовать различные очереди для каждого источника событий, а затем использовать набор очередей для блокировки на всех очередях сразу. Вместо этого стек UDP/IP:
Определение структуры показано ниже.
/*----------------------------------------------------------------------------*/
typedef struct IP_TASK_COMMANDS
{
/* Сообщает принимающей задаче, что это за событие. */
eIPEvent_t eEventType;
/* Содержит либо сами данные, связанные с этим событием, либо указатель
на них. */
void *pvData;
} xIPStackEvent_t;
Пример использования этой структуры:
Задача обслуживания UDP/IP обрабатывает события, используя простой цикл:
/*----------------------------------------------------------------------------*/
/* Переменная, используемая для получения данных из очереди. */
xIPStackEvent_t xReceivedEvent;
for( ;; )
{
/* Ждём поступления события. */
xQueueReceive( xNetworkEventQueue, &xReceivedEvent, portMAX_DELAY );
/* Для каждого типа события выполняем соответствующие действия. */
switch( xReceivedEvent.eEventType )
{
case eNetworkDownEvent :
prvProcessNetworkDownEvent();
break;
case eEthernetRxEvent :
prvProcessEthernetFrame( xReceivedEvent.pvData );
break;
case eARPTimerEvent :
prvAgeARPCache();
break;
case eStackTxEvent :
prvProcessGeneratedPacket( xReceivedEvent.pvData );
break;
case eDHCPEvent:
vDHCPProcess();
break;
default :
/* Should not get here. */
break;
}
}