Semaphores help control access to shared resources so tasks do not interfere with each other. This avoids data corruption and unpredictable behavior.
SemaphoreHandle_t sem; int counter = 0; void Task1(void *pvParameters) { xSemaphoreTake(sem, portMAX_DELAY); counter += 1; printf("Task1 counter: %d\n", counter); xSemaphoreGive(sem); vTaskDelete(NULL); } void Task2(void *pvParameters) { xSemaphoreTake(sem, portMAX_DELAY); counter += 2; printf("Task2 counter: %d\n", counter); xSemaphoreGive(sem); vTaskDelete(NULL); } int main() { sem = xSemaphoreCreateBinary(); xSemaphoreGive(sem); xTaskCreate(Task1, "T1", 1000, NULL, 1, NULL); xTaskCreate(Task2, "T2", 1000, NULL, 1, NULL); vTaskStartScheduler(); return 0; }
The semaphore allows only one task to update the counter at a time. Task1 adds 1 first, then Task2 adds 2, so the final counter after Task2 is 3.
int counter = 0; void Task1(void *pvParameters) { counter += 1; printf("Task1 counter: %d\n", counter); vTaskDelete(NULL); } void Task2(void *pvParameters) { counter += 2; printf("Task2 counter: %d\n", counter); vTaskDelete(NULL); } int main() { xTaskCreate(Task1, "T1", 1000, NULL, 1, NULL); xTaskCreate(Task2, "T2", 1000, NULL, 1, NULL); vTaskStartScheduler(); return 0; }
Without a semaphore, both tasks can update the counter simultaneously, causing a race condition. This leads to unpredictable and incorrect counter values.
Binary semaphores are created with xSemaphoreCreateBinary() and must be given once before use. Counting semaphores and mutexes are different types.
A binary semaphore is ideal to signal the consumer when data is ready. Counting semaphores count multiple events, mutexes protect shared data but do not signal, and shared variables alone do not synchronize.
