Resource manager task pattern in FreeRTOS - Time & Space Complexity
When using a resource manager task in FreeRTOS, it's important to know how the time to handle requests grows as more tasks ask for resources.
We want to see how the work inside the manager changes when the number of requests increases.
Analyze the time complexity of the following code snippet.
void ResourceManagerTask(void *pvParameters) {
ResourceRequest_t request;
for (;;) {
if (xQueueReceive(requestQueue, &request, portMAX_DELAY) == pdPASS) {
// Process request
AllocateResource(request.id);
xQueueSend(responseQueue, &request.id, 0);
}
}
}
This task waits for resource requests from other tasks, processes each request one by one, and sends back a response.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The infinite loop that waits and processes each request from the queue.
- How many times: Once per request received, repeating indefinitely as requests come in.
Each new request causes the task to do a fixed amount of work to allocate and respond.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 resource allocations and responses |
| 100 | 100 resource allocations and responses |
| 1000 | 1000 resource allocations and responses |
Pattern observation: The work grows directly with the number of requests, one by one.
Time Complexity: O(n)
This means the time to handle requests grows linearly as more requests come in.
[X] Wrong: "The resource manager handles all requests instantly, so time does not grow with more requests."
[OK] Correct: Each request must be processed one at a time, so more requests mean more total work and longer total processing time.
Understanding how tasks handle requests helps you design systems that stay responsive as load grows. This skill shows you can think about real-time system behavior clearly.
"What if the resource manager processed multiple requests in parallel? How would the time complexity change?"
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
