Counting semaphore for resource pools in FreeRTOS - Time & Space Complexity
We want to understand how the time to take or give a counting semaphore changes as the number of waiting tasks grows.
How does the system handle waiting and releasing resources when many tasks compete?
Analyze the time complexity of the following code snippet.
// Create a counting semaphore with max count 5
SemaphoreHandle_t xSemaphore = xSemaphoreCreateCounting(5, 5);
// Task tries to take a resource
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
// Use the resource
// ...
// Release the resource
xSemaphoreGive(xSemaphore);
}
This code manages access to a pool of 5 identical resources using a counting semaphore.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Taking and giving the semaphore to access resources.
- How many times: Constant time per take/give; no loops that scale with queue length. Internally manages queue with O(1) enqueue/dequeue.
As the number of tasks waiting grows, the time to take or give remains constant.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 5-10 queue operations |
| 100 | About 5-10 queue operations |
| 1000 | About 5-10 queue operations |
Pattern observation: The work per operation remains constant regardless of the number of waiting tasks.
Time Complexity: O(1)
This means the time to manage the semaphore and waiting tasks per operation remains constant, independent of the number of tasks waiting.
[X] Wrong: "Taking or giving a counting semaphore takes longer as more tasks wait because it scans the queue."
[OK] Correct: FreeRTOS uses doubly-linked lists for efficient O(1) enqueue (tail) and dequeue (head) operations. Each give wakes only one task.
Understanding how resource management scales helps you design systems that stay responsive even when many tasks compete for limited resources.
"What if the semaphore was binary instead of counting? How would the time complexity change when many tasks wait?"
Practice
Solution
Step 1: Understand counting semaphore role
A counting semaphore keeps track of how many identical resources are free or in use.Step 2: Compare with other options
Creating tasks, storing data, or handling interrupts are not roles of counting semaphores.Final Answer:
To track the number of available identical resources -> Option AQuick Check:
Counting semaphore = resource count tracker [OK]
- Confusing counting semaphore with binary semaphore
- Thinking it creates or manages tasks
- Assuming it stores data
Solution
Step 1: Recall function parameters
The functionxSemaphoreCreateCountingtakes max count first, then initial count.Step 2: Match parameters to options
xSemaphoreCreateCounting(5, 3); uses (5, 3) which means max count 5 and initial count 3, correct order.Final Answer:
xSemaphoreCreateCounting(5, 3); -> Option BQuick Check:
Max count first, initial count second [OK]
- Swapping max and initial count parameters
- Using only one parameter
- Confusing with binary semaphore creation
SemaphoreHandle_t sem = xSemaphoreCreateCounting(3, 3); xSemaphoreTake(sem, 0); xSemaphoreTake(sem, 0);
Solution
Step 1: Understand initial semaphore count
The semaphore starts with count 3 (max and initial both 3).Step 2: Subtract count for each take
EachxSemaphoreTakereduces count by 1 if successful. Two takes reduce count by 2.Final Answer:
1 -> Option DQuick Check:
3 - 2 takes = 1 [OK]
- Assuming count stays the same after take
- Confusing take with give operation
- Thinking count can go below zero
SemaphoreHandle_t sem = xSemaphoreCreateCounting(2, 2); xSemaphoreGive(sem);
Solution
Step 1: Check initial semaphore count
The semaphore is created with max count 2 and initial count 2, so it's full.Step 2: Analyze xSemaphoreGive call
Giving semaphore when count is already max causes overflow error or undefined behavior.Final Answer:
Calling xSemaphoreGive when semaphore count is at max causes overflow -> Option CQuick Check:
Giving at max count causes overflow [OK]
- Ignoring semaphore max count limits
- Swapping max and initial counts
- Calling give before creating semaphore
Solution
Step 1: Identify max and initial counts
Max count is total devices (4), initial count is free devices (2).Step 2: Match parameters to function call
Correct call isxSemaphoreCreateCounting(4, 2)with max 4 and initial 2.Final Answer:
SemaphoreHandle_t sem = xSemaphoreCreateCounting(4, 2); -> Option AQuick Check:
Max = total devices, initial = free devices [OK]
- Swapping max and initial counts
- Setting initial count higher than max
- Using max count less than total resources
Ready to prove it?
Pass the test and this pattern moves unknown
