Task notifications and queues are ways tasks in FreeRTOS communicate. Understanding their speed helps you pick the best one for your program.
Task notification vs queue performance in FreeRTOS
/* Task Notification Example */ void vTaskFunction(void *pvParameters) { uint32_t ulNotificationValue; for (;;) { /* Wait for notification */ xTaskNotifyWait(0x00, 0xffffffff, &ulNotificationValue, portMAX_DELAY); /* Process notification value */ } } /* Queue Example */ QueueHandle_t xQueue; void vSenderTask(void *pvParameters) { int dataToSend = 100; for (;;) { xQueueSend(xQueue, &dataToSend, portMAX_DELAY); } } void vReceiverTask(void *pvParameters) { int receivedData; for (;;) { xQueueReceive(xQueue, &receivedData, portMAX_DELAY); /* Process receivedData */ } }
Task notifications are like fast signals with optional 32-bit data.
Queues can hold multiple items and are more flexible but slower.
/* Empty queue scenario */ QueueHandle_t xQueue = xQueueCreate(5, sizeof(int)); int receivedValue; if (xQueueReceive(xQueue, &receivedValue, 0) == pdPASS) { // Got data } else { // Queue empty }
/* Single element notification */ uint32_t notificationValue = 0; xTaskNotifyGive(taskHandle); if (xTaskNotifyWait(0, 0xffffffff, ¬ificationValue, portMAX_DELAY) == pdTRUE) { // Notification received }
/* Notification at task start */ // Task waits indefinitely for notification before proceeding xTaskNotifyWait(0, 0xffffffff, NULL, portMAX_DELAY);
/* Queue full scenario */ QueueHandle_t xQueue = xQueueCreate(2, sizeof(int)); int data = 10; xQueueSend(xQueue, &data, 0); xQueueSend(xQueue, &data, 0); BaseType_t result = xQueueSend(xQueue, &data, 0); // result will be errQUEUE_FULL
This program creates two tasks: one waits for a task notification, the other waits for data from a queue. It sends a notification and queue data, then prints what each task receives.
#include "FreeRTOS.h" #include "task.h" #include "queue.h" #include <stdio.h> QueueHandle_t xQueue; TaskHandle_t xTaskHandle; void vTaskNotificationReceiver(void *pvParameters) { uint32_t ulNotificationValue; printf("TaskNotificationReceiver: Waiting for notification...\n"); xTaskNotifyWait(0x00, 0xffffffff, &ulNotificationValue, portMAX_DELAY); printf("TaskNotificationReceiver: Received notification with value %lu\n", ulNotificationValue); vTaskDelete(NULL); } void vQueueReceiver(void *pvParameters) { int receivedValue; printf("QueueReceiver: Waiting for queue data...\n"); xQueueReceive(xQueue, &receivedValue, portMAX_DELAY); printf("QueueReceiver: Received queue data %d\n", receivedValue); vTaskDelete(NULL); } int main(void) { xQueue = xQueueCreate(1, sizeof(int)); if (xQueue == NULL) { printf("Failed to create queue\n"); return 1; } xTaskCreate(vTaskNotificationReceiver, "NotifyReceiver", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle); xTaskCreate(vQueueReceiver, "QueueReceiver", configMINIMAL_STACK_SIZE, NULL, 1, NULL); printf("Sending notification to task...\n"); xTaskNotifyGive(xTaskHandle); int dataToSend = 42; printf("Sending data to queue...\n"); xQueueSend(xQueue, &dataToSend, 0); vTaskStartScheduler(); // Should never reach here return 0; }
Task notifications are faster because they avoid the overhead of queues and copying data.
Queues use more memory and CPU time but can hold multiple messages and larger data.
Common mistake: Using task notifications for large or multiple messages instead of queues.
Use task notifications for simple signaling or small data; use queues for complex or multiple messages.
Task notifications are lightweight and fast for simple signals.
Queues are flexible and can hold multiple or larger messages but are slower.
Choose based on your data size and communication needs.
Practice
Solution
Step 1: Understand task notifications
Task notifications are designed as lightweight signals between tasks, using minimal resources.Step 2: Compare with queues
Queues provide more flexibility but require more memory and processing time, making them slower.Final Answer:
Task notifications are faster and use less memory than queues. -> Option CQuick Check:
Task notifications = faster, less memory [OK]
- Thinking queues are always faster
- Confusing signaling with data transfer
- Assuming task notifications can hold large data
Solution
Step 1: Identify task notification sending functions
The functionxTaskNotifyGive()is used to send a notification to a task.Step 2: Differentiate from queue functions
xQueueSend()andxQueueReceive()are queue operations, not task notifications.Final Answer:
xTaskNotifyGive(taskHandle); -> Option AQuick Check:
Send notification = xTaskNotifyGive() [OK]
- Using queue functions to send notifications
- Confusing xTaskNotifySend with xTaskNotifyGive
- Incorrect parameters in notification functions
uint32_t value = 0;
if (xTaskNotifyWait(0x00, 0xFFFFFFFF, &value, 0) == pdTRUE) {
// Notification received
process(value);
} else {
// No notification
process(0);
}
What will happen if a task notification with value 5 was sent before this check?Solution
Step 1: Understand xTaskNotifyWait behavior
This function checks for a notification and retrieves its value if available, returning pdTRUE.Step 2: Analyze the timeout and notification value
Since a notification with value 5 was sent before, the function returns immediately with pdTRUE and sets value to 5.Final Answer:
process(5) will be called because notification value is received. -> Option BQuick Check:
Notification received = process(value) [OK]
- Assuming zero timeout causes blocking
- Ignoring the notification value received
- Thinking uninitialized value causes error
uint32_t notifyValue;
if (xTaskNotifyWait(0, 0xFFFFFFFF, Β¬ifyValue, portMAX_DELAY) == pdTRUE) {
// Process notification
process(notifyValue);
}
// Later
xQueueSend(queueHandle, &data, 0);Solution
Step 1: Analyze xTaskNotifyWait usage
UsingportMAX_DELAYcauses the task to block indefinitely until a notification arrives.Step 2: Consider implications
This indefinite block can cause deadlocks if notifications are not sent, which is a common issue.Final Answer:
Using portMAX_DELAY in xTaskNotifyWait can cause indefinite blocking. -> Option DQuick Check:
portMAX_DELAY = indefinite block risk [OK]
- Ignoring blocking behavior of portMAX_DELAY
- Assuming notifyValue must be initialized
- Confusing queue and notification usage
Solution
Step 1: Understand task notifications limitations
Task notifications are fast but designed for simple signals or small data (like a single 32-bit value).Step 2: Consider queues for multiple data items
Queues can hold multiple messages and maintain order, suitable for sending multiple integers reliably.Step 3: Choose best practice
Use task notifications for signaling and queues for actual data transfer to balance performance and correctness.Final Answer:
Use task notifications only for signaling and queues for data transfer. -> Option AQuick Check:
Notifications = signals, queues = data [OK]
- Trying to encode multiple values in notifications
- Ignoring data integrity with global variables
- Assuming notifications can replace queues for data
Ready to prove it?
Pass the test and this pattern moves unknown
