📖 Scenario: You are working on a FreeRTOS project where two tasks need to share a resource safely. To do this, you will use a binary semaphore to control access.
🎯 Goal: Create a binary semaphore, use it to synchronize two tasks, and print messages showing when each task takes and gives the semaphore.
📋 What You'll Learn
Create a binary semaphore using FreeRTOS API
Create two tasks that use the semaphore to synchronize access
Use xSemaphoreTake and xSemaphoreGive correctly
Print messages when tasks take and give the semaphore
💡 Why This Matters
🌍 Real World
Binary semaphores are used in embedded systems to protect shared resources like sensors or communication buses from being accessed by multiple tasks at the same time.
💼 Career
Understanding binary semaphores is essential for embedded software developers working with real-time operating systems to ensure safe and predictable task synchronization.
Progress0 / 4 steps
1
Create a binary semaphore
Create a binary semaphore handle called xBinarySemaphore and initialize it using xSemaphoreCreateBinary().
FreeRTOS
Hint
Use SemaphoreHandle_t type for the semaphore handle and xSemaphoreCreateBinary() to create it.
2
Create two tasks to use the semaphore
Create two tasks called vTask1 and vTask2 using xTaskCreate(). Each task should take a void *pvParameters argument.
FreeRTOS
Hint
Define two functions vTask1 and vTask2 with void *pvParameters parameter. Use xTaskCreate() to create them.
3
Use the semaphore in the tasks
Inside vTask1 and vTask2, use xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) to wait for the semaphore, then print "Task 1 took semaphore" or "Task 2 took semaphore". After that, use xSemaphoreGive(xBinarySemaphore) to release it.
FreeRTOS
Hint
Use xSemaphoreTake with portMAX_DELAY to wait indefinitely. Use printf to show messages. Then release with xSemaphoreGive.
4
Print the semaphore usage output
Print the messages from both tasks when they take the semaphore. The output should show Task 1 took semaphore and Task 2 took semaphore on separate lines.
FreeRTOS
Hint
Call vTaskStartScheduler() to start running the tasks and see the output.
Practice
(1/5)
1. What is the primary purpose of a binary semaphore in FreeRTOS?
easy
A. To store multiple values for task communication
B. To signal and control access to shared resources between tasks
C. To create multiple tasks automatically
D. To allocate memory dynamically
Solution
Step 1: Understand the role of binary semaphores
Binary semaphores are used to signal availability or control access to resources between tasks.
Step 2: Compare options with this role
Only To signal and control access to shared resources between tasks describes signaling and controlling access, which matches the purpose of binary semaphores.
Final Answer:
To signal and control access to shared resources between tasks -> Option B
Quick Check:
Binary semaphore = resource signaling [OK]
Hint: Binary semaphore controls resource access between tasks [OK]
Common Mistakes:
Confusing binary semaphore with counting semaphore
Thinking it stores multiple values
Assuming it creates tasks
2. Which of the following is the correct way to create a binary semaphore in FreeRTOS?
easy
A. xSemaphoreCreateBinary();
B. xSemaphoreCreateCounting(1, 0);
C. xSemaphoreCreateMutex();
D. xSemaphoreCreateBinary(1);
Solution
Step 1: Recall the function to create a binary semaphore
The correct function is xSemaphoreCreateBinary() with no parameters.
Step 2: Check each option
xSemaphoreCreateBinary(); matches the correct function. xSemaphoreCreateCounting(1, 0); creates a counting semaphore, C creates a mutex, and D is invalid syntax.
A. Task1 will enter the critical section immediately
B. Task1 will skip the critical section
C. Task1 will cause a runtime error
D. Task1 will block indefinitely until Task2 gives the semaphore
Solution
Step 1: Analyze xSemaphoreTake with portMAX_DELAY
Task1 calls xSemaphoreTake with portMAX_DELAY, so it waits indefinitely for the semaphore.
Step 2: Consider initial semaphore state and Task2 action
The semaphore is created but not given initially, so Task1 blocks until Task2 calls xSemaphoreGive.
Final Answer:
Task1 will block indefinitely until Task2 gives the semaphore -> Option D
Quick Check:
xSemaphoreTake with portMAX_DELAY blocks until given [OK]
Hint: xSemaphoreTake with portMAX_DELAY waits until given [OK]
Common Mistakes:
Assuming semaphore is initially available
Thinking Task1 runs critical section immediately
Confusing blocking with error
4. Identify the error in this FreeRTOS binary semaphore usage:
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();
void Task(void *pvParameters) {
if (xSemaphoreTake(xBinarySemaphore, 0) == pdTRUE) {
// Do work
xSemaphoreGive(xBinarySemaphore);
}
}
medium
A. xSemaphoreCreateBinary requires a parameter
B. xSemaphoreGive should be called before xSemaphoreTake
C. Semaphore is never given before take, so take always fails
D. xSemaphoreTake timeout cannot be zero
Solution
Step 1: Check initial semaphore state after creation
xSemaphoreCreateBinary creates a semaphore that is initially empty (not given).
Step 2: Analyze xSemaphoreTake with zero timeout
With zero timeout, xSemaphoreTake returns immediately. Since semaphore is empty, it returns pdFALSE, so the if block never runs.
Final Answer:
Semaphore is never given before take, so take always fails -> Option C
Quick Check:
Binary semaphore empty at creation, take with zero timeout fails [OK]
Hint: Binary semaphore must be given before take succeeds [OK]
Common Mistakes:
Assuming semaphore is initially given
Thinking zero timeout means wait forever
Confusing function parameters
5. You want to synchronize two tasks so that Task B only runs after Task A signals completion using a binary semaphore. Which sequence correctly implements this?
hard
A. Task A calls xSemaphoreGive() after work; Task B calls xSemaphoreTake() with portMAX_DELAY before work
B. Task B calls xSemaphoreGive() before work; Task A calls xSemaphoreTake() after work
C. Both tasks call xSemaphoreTake() simultaneously; semaphore is given once at start
D. Task A and Task B both call xSemaphoreGive() without taking
Solution
Step 1: Understand synchronization with binary semaphore
Task B must wait for Task A's signal, so Task B should take the semaphore and block until given.
Step 2: Match sequence to this logic
Task A gives the semaphore after finishing work; Task B takes it with portMAX_DELAY to wait indefinitely.
Final Answer:
Task A calls xSemaphoreGive() after work; Task B calls xSemaphoreTake() with portMAX_DELAY before work -> Option A
Quick Check:
Give after work, take before work = sync tasks [OK]
Hint: Give semaphore after work; take before work to sync tasks [OK]
Common Mistakes:
Reversing give and take roles
Both tasks giving without taking
Taking without giving semaphore
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.