The resource manager task pattern helps control access to shared resources safely in FreeRTOS. It avoids conflicts by letting one task manage the resource requests.
Resource manager task pattern in FreeRTOS
/* Pseudocode for resource manager task pattern in FreeRTOS */ // Resource manager task function void ResourceManagerTask(void *params) { for (;;) { // Wait for resource request message ResourceRequest req; ReceiveRequest(&req); // Process request (e.g., lock resource) AccessResource(req); // Notify requester when done NotifyRequester(req); } } // Other tasks send requests void ClientTask(void *params) { ResourceRequest req = CreateRequest(); SendRequestToManager(&req); WaitForResponse(&req); UseResource(); }
The resource manager task runs in a loop, handling requests one by one.
Communication between tasks usually uses queues or message buffers.
// Example: Sending a request to resource manager
ResourceRequest req = { .taskHandle = xTaskGetCurrentTaskHandle(), .action = READ };
xQueueSend(resourceQueue, &req, portMAX_DELAY);// Resource manager receives and processes request
ResourceRequest req;
xQueueReceive(resourceQueue, &req, portMAX_DELAY);
// Perform resource action
ProcessRequest(req);
// Notify client task
xTaskNotifyGive(req.taskHandle);This program creates a resource manager task and two client tasks. Clients send requests to the manager via a queue. The manager processes requests one by one and notifies clients when done.
#include "FreeRTOS.h" #include "task.h" #include "queue.h" #include <stdio.h> // Define a simple request struct typedef struct { TaskHandle_t requester; int action; // 0 = read, 1 = write } ResourceRequest; QueueHandle_t resourceQueue; void ResourceManagerTask(void *params) { ResourceRequest req; for (;;) { if (xQueueReceive(resourceQueue, &req, portMAX_DELAY) == pdPASS) { // Simulate resource access if (req.action == 0) { printf("ResourceManager: Reading resource for task %p\n", req.requester); } else { printf("ResourceManager: Writing resource for task %p\n", req.requester); } // Notify requester task xTaskNotifyGive(req.requester); } } } void ClientTask(void *params) { ResourceRequest req = { .requester = xTaskGetCurrentTaskHandle(), .action = (int)params }; printf("ClientTask %p: Sending request action %d\n", req.requester, req.action); xQueueSend(resourceQueue, &req, portMAX_DELAY); // Wait for resource manager to finish ulTaskNotifyTake(pdTRUE, portMAX_DELAY); printf("ClientTask %p: Resource access done\n", req.requester); vTaskDelete(NULL); } int main(void) { resourceQueue = xQueueCreate(5, sizeof(ResourceRequest)); xTaskCreate(ResourceManagerTask, "ResourceManager", 1000, NULL, 2, NULL); xTaskCreate(ClientTask, "Client1", 1000, (void *)0, 1, NULL); // read xTaskCreate(ClientTask, "Client2", 1000, (void *)1, 1, NULL); // write vTaskStartScheduler(); for (;;) {} return 0; }
Use queues or message buffers for communication between tasks.
Always notify the requesting task after resource access to avoid deadlocks.
Keep the resource manager task priority higher than clients to ensure timely handling.
The resource manager task pattern centralizes control of shared resources.
Tasks send requests to the manager instead of accessing resources directly.
This pattern prevents conflicts and makes resource sharing safe and organized.
Practice
Resource Manager Task Pattern in FreeRTOS?Solution
Step 1: Understand resource sharing challenges
When multiple tasks access shared resources directly, conflicts and data corruption can occur.Step 2: Role of Resource Manager Task
The Resource Manager Task centralizes access, so tasks send requests to it instead of accessing resources directly, preventing conflicts.Final Answer:
To centralize control of shared resources and prevent conflicts -> Option AQuick Check:
Centralized control = Prevent conflicts [OK]
- Thinking tasks access resources directly
- Assuming it increases CPU usage
- Believing it removes synchronization needs
Solution
Step 1: Identify communication method
Resource Manager Tasks typically receive requests via queues to serialize access.Step 2: Evaluate options
Only Using a queue to send a request message to the manager task uses a queue to send requests, which is the correct and safe method.Final Answer:
Using a queue to send a request message to the manager task -> Option AQuick Check:
Queue communication = Correct request method [OK]
- Accessing shared variables directly
- Ignoring synchronization
- Using global variables without communication
typedef struct {
int command;
int data;
} RequestMessage;
QueueHandle_t resourceQueue;
void ResourceManagerTask(void *params) {
RequestMessage req;
while (1) {
if (xQueueReceive(resourceQueue, &req, portMAX_DELAY) == pdPASS) {
if (req.command == 1) {
printf("Processed data: %d\n", req.data * 2);
}
}
}
}
void ClientTask(void *params) {
RequestMessage msg = {1, 5};
xQueueSend(resourceQueue, &msg, 0);
vTaskDelete(NULL);
}Solution
Step 1: Analyze ClientTask sending message
ClientTask sends a message with command=1 and data=5 to the resourceQueue.Step 2: Analyze ResourceManagerTask processing
ResourceManagerTask receives the message, checks command==1, then prints data*2 = 5*2 = 10.Final Answer:
Processed data: 10 -> Option BQuick Check:
Data 5 doubled = 10 output [OK]
- Confusing data value with output
- Assuming no message received
- Ignoring the multiplication by 2
void ResourceManagerTask(void *params) {
RequestMessage req;
while (1) {
if (xQueueReceive(resourceQueue, &req, 0) == pdPASS) {
if (req.command == 1) {
// Process command
}
}
}
}
What is the problem?Solution
Step 1: Understand xQueueReceive block time
Using 0 as block time means the call returns immediately if queue is empty, possibly missing messages.Step 2: Effect on Resource Manager Task
The task may spin without waiting, causing high CPU usage and missed processing.Final Answer:
Using zero block time causes missed messages if queue is empty -> Option DQuick Check:
Zero block time = possible missed messages [OK]
- Ignoring block time effect
- Thinking struct is undefined
- Believing while loop is wrong
Solution
Step 1: Consider centralized control for multiple resources
A single Resource Manager Task can handle multiple resource types by differentiating requests.Step 2: Use message struct with resource type and command
This allows the manager task to use a switch-case to process requests efficiently and safely.Final Answer:
Use a single queue with a message struct containing resource type and command fields, then switch-case inside the manager task -> Option CQuick Check:
Single queue + message struct = efficient multi-resource management [OK]
- Creating multiple manager tasks unnecessarily
- Allowing direct resource access with mutexes
- Using global variables without communication
Ready to prove it?
Pass the test and this pattern moves unknown
