MCU & FPGA RTOS FreeRTOS: Uso Correto de Queue com Múltiplos Consumidores

FreeRTOS: Uso Correto de Queue com Múltiplos Consumidores

Introdução: filas no FreeRTOS e o cenário de múltiplos consumidores

No FreeRTOS, Queue é um dos mecanismos centrais de comunicação e sincronização entre tarefas. Diferente de simples buffers, uma fila carrega não apenas dados, mas também semântica de sincronização, permitindo que tarefas produtoras e consumidoras operem de forma desacoplada no tempo. Em sistemas reais — especialmente em firmware para sensores, comunicação, aquisição de dados e pipelines de processamento — é muito comum termos um produtor e vários consumidores, todos interessados nos dados que chegam pela mesma fila.

O primeiro ponto importante, e frequentemente negligenciado, é que uma Queue do FreeRTOS não é um mecanismo de broadcast. Ela segue estritamente o modelo FIFO (First-In, First-Out) com remoção destrutiva do item. Isso significa que, quando múltiplas tarefas consumidoras bloqueiam na mesma fila, apenas uma delas receberá cada item enviado, e essa escolha é feita pelo escalonador com base em prioridade e estado das tarefas. Esse detalhe muda completamente a forma como o sistema deve ser arquitetado.

Esse comportamento é ideal quando os consumidores representam workers concorrentes, ou seja, tarefas equivalentes que disputam trabalho. Um exemplo clássico é um sistema em que uma interrupção de ADC empilha amostras em uma fila, e várias tarefas de processamento estatístico competem para consumir esses dados. Nesse caso, a fila atua como um work queue, balanceando carga automaticamente entre os consumidores.

Por outro lado, quando o objetivo é que todos os consumidores vejam todos os eventos, a Queue isoladamente é a escolha errada. Muitos bugs em sistemas embarcados com FreeRTOS surgem exatamente desse equívoco conceitual: o desenvolvedor assume que várias tarefas “escutando” a mesma fila receberão as mesmas mensagens, o que simplesmente não acontece. Esse erro se manifesta como perda intermitente de eventos, estados inconsistentes e falhas difíceis de reproduzir.

Para ilustrar o cenário correto de múltiplos consumidores concorrentes, considere o exemplo abaixo, onde várias tarefas processam mensagens vindas de um único produtor:

typedef struct {
    uint32_t id;
    uint16_t value;
} message_t;

QueueHandle_t xQueue;

void vProducerTask(void *pvParameters)
{
    message_t msg;
    uint32_t counter = 0;

    for (;;)
    {
        msg.id = counter++;
        msg.value = counter * 10;

        xQueueSend(xQueue, &msg, portMAX_DELAY);
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void vConsumerTask(void *pvParameters)
{
    message_t msg;

    for (;;)
    {
        if (xQueueReceive(xQueue, &msg, portMAX_DELAY) == pdPASS)
        {
            /* Cada mensagem será processada por APENAS um consumidor */
            process_message(&msg);
        }
    }
}

Nesse modelo, várias instâncias de vConsumerTask podem ser criadas, e cada mensagem enviada pelo produtor será entregue a apenas uma delas. O FreeRTOS garante exclusão mútua implícita no acesso à fila, evitando a necessidade de mutex para esse fluxo específico.

Nesta artigo, vamos aprofundar quando esse modelo é ideal, quais implicações surgem em termos de escalonamento, prioridade e starvation, como evitar armadilhas comuns, e quais alternativas arquiteturais devem ser usadas quando o requisito é difusão (fan-out) e não competição.

0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x