0
0
FreeRTOSprogramming~7 mins

Task pooling for dynamic workloads in FreeRTOS

Choose your learning style9 modes available
Introduction

Task pooling helps manage many small jobs efficiently by reusing a fixed number of tasks instead of creating and deleting tasks repeatedly.

When you have many short tasks arriving at unpredictable times.
When creating and deleting tasks frequently wastes system resources.
When you want to limit the number of active tasks to save memory.
When tasks perform similar work but with different data.
When you want to improve system responsiveness by reusing tasks.
Syntax
FreeRTOS
/* Create a fixed number of worker tasks */
for (int i = 0; i < POOL_SIZE; i++) {
    xTaskCreate(workerTask, "Worker", STACK_SIZE, NULL, PRIORITY, &taskHandles[i]);
}

/* Use a queue to send work items to the pool */
QueueHandle_t workQueue = xQueueCreate(QUEUE_LENGTH, sizeof(WorkItem));

/* Worker task function */
void workerTask(void *params) {
    WorkItem item;
    while (1) {
        if (xQueueReceive(workQueue, &item, portMAX_DELAY) == pdPASS) {
            processWorkItem(&item);
        }
    }
}

Use a queue to send work items to the pool of tasks.

Worker tasks wait on the queue and process items as they arrive.

Examples
This defines the data each task will process.
FreeRTOS
/* Define work item structure */
typedef struct {
    int jobId;
    char data[20];
} WorkItem;
Creates a queue for 10 work items and 3 worker tasks.
FreeRTOS
/* Create work queue and tasks */
workQueue = xQueueCreate(10, sizeof(WorkItem));
for (int i = 0; i < 3; i++) {
    xTaskCreate(workerTask, "Worker", 1000, NULL, 2, NULL);
}
Adds a new job to the queue for workers to pick up.
FreeRTOS
/* Send work to the queue */
WorkItem newJob = {1, "Task data"};
xQueueSend(workQueue, &newJob, 0);
Sample Program

This program creates a pool of 2 worker tasks and a queue. It sends 3 jobs to the queue. Each worker waits for jobs and processes them by printing the job info.

FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <stdio.h>

#define POOL_SIZE 2
#define STACK_SIZE 1000
#define PRIORITY 2

typedef struct {
    int jobId;
    char data[20];
} WorkItem;

QueueHandle_t workQueue;

void processWorkItem(WorkItem *item) {
    printf("Processing job %d with data: %s\n", item->jobId, item->data);
    vTaskDelay(pdMS_TO_TICKS(500)); // Simulate work
}

void workerTask(void *params) {
    WorkItem item;
    while (1) {
        if (xQueueReceive(workQueue, &item, portMAX_DELAY) == pdPASS) {
            processWorkItem(&item);
        }
    }
}

int main(void) {
    workQueue = xQueueCreate(5, sizeof(WorkItem));
    for (int i = 0; i < POOL_SIZE; i++) {
        xTaskCreate(workerTask, "Worker", STACK_SIZE, NULL, PRIORITY, NULL);
    }

    WorkItem jobs[] = {
        {1, "Data A"},
        {2, "Data B"},
        {3, "Data C"}
    };

    for (int i = 0; i < 3; i++) {
        xQueueSend(workQueue, &jobs[i], 0);
    }

    vTaskStartScheduler();
    return 0;
}
OutputSuccess
Important Notes

Make sure the queue size matches the expected workload to avoid lost jobs.

Worker tasks run forever, so they should be designed to handle all jobs safely.

Use vTaskDelay or blocking calls to avoid busy waiting and save CPU.

Summary

Task pooling reuses a fixed number of tasks to handle many jobs efficiently.

Use a queue to send work items to the pool of worker tasks.

This approach saves memory and improves responsiveness for dynamic workloads.