A binary semaphore helps two parts of a program talk to each other safely. It makes sure only one part uses a resource at a time.
Binary semaphore creation and usage in FreeRTOS
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary(); // To take (wait for) the semaphore if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) { // Access resource safely } // To give (release) the semaphore xSemaphoreGive(xSemaphore);
xSemaphoreCreateBinary() creates a binary semaphore that starts empty (taken).
xSemaphoreTake() waits for the semaphore to be available. xSemaphoreGive() releases it.
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary(); // Give semaphore initially to make it available xSemaphoreGive(xSemaphore);
if (xSemaphoreTake(xSemaphore, 1000) == pdTRUE) { // Got the semaphore within 1000 ticks } else { // Timeout waiting for semaphore }
void vTask1(void *pvParameters) {
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
// Use shared resource
xSemaphoreGive(xSemaphore);
}
vTaskDelete(NULL);
}This program creates a binary semaphore and two tasks. Task2 gives the semaphore to start Task1. Task1 waits for the semaphore, prints messages, simulates work, then releases the semaphore.
#include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include <stdio.h> SemaphoreHandle_t xBinarySemaphore; void vTask1(void *pvParameters) { printf("Task1: Waiting for semaphore...\n"); if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) { printf("Task1: Got semaphore!\n"); // Simulate work vTaskDelay(pdMS_TO_TICKS(500)); printf("Task1: Releasing semaphore.\n"); xSemaphoreGive(xBinarySemaphore); } vTaskDelete(NULL); } void vTask2(void *pvParameters) { printf("Task2: Giving semaphore to start Task1.\n"); xSemaphoreGive(xBinarySemaphore); vTaskDelete(NULL); } int main(void) { xBinarySemaphore = xSemaphoreCreateBinary(); if (xBinarySemaphore == NULL) { printf("Failed to create semaphore.\n"); return 1; } xTaskCreate(vTask1, "Task1", 1000, NULL, 1, NULL); xTaskCreate(vTask2, "Task2", 1000, NULL, 1, NULL); vTaskStartScheduler(); // Should never reach here for(;;); return 0; }
Binary semaphores only have two states: available or taken.
Always check if semaphore creation returns NULL to avoid errors.
Use portMAX_DELAY to wait forever for a semaphore.
Binary semaphores help tasks share resources safely by signaling availability.
Create with xSemaphoreCreateBinary(), take with xSemaphoreTake(), and give with xSemaphoreGive().
Use them to coordinate tasks or handle events in FreeRTOS.
Practice
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 BQuick Check:
Binary semaphore = resource signaling [OK]
- Confusing binary semaphore with counting semaphore
- Thinking it stores multiple values
- Assuming it creates tasks
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.Final Answer:
xSemaphoreCreateBinary(); -> Option AQuick Check:
Create binary semaphore = xSemaphoreCreateBinary() [OK]
- Using counting semaphore creation instead
- Adding parameters to xSemaphoreCreateBinary()
- Confusing mutex creation with binary semaphore
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();
void Task1(void *pvParameters) {
if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
// Critical section
}
}
void Task2(void *pvParameters) {
xSemaphoreGive(xBinarySemaphore);
}
What will happen when Task1 runs before Task2?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 DQuick Check:
xSemaphoreTake with portMAX_DELAY blocks until given [OK]
- Assuming semaphore is initially available
- Thinking Task1 runs critical section immediately
- Confusing blocking with error
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();
void Task(void *pvParameters) {
if (xSemaphoreTake(xBinarySemaphore, 0) == pdTRUE) {
// Do work
xSemaphoreGive(xBinarySemaphore);
}
}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 CQuick Check:
Binary semaphore empty at creation, take with zero timeout fails [OK]
- Assuming semaphore is initially given
- Thinking zero timeout means wait forever
- Confusing function parameters
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 AQuick Check:
Give after work, take before work = sync tasks [OK]
- Reversing give and take roles
- Both tasks giving without taking
- Taking without giving semaphore
Ready to prove it?
Pass the test and this pattern moves unknown
