// MUTEX EXAMPLE 2024-2025
// DEVELOPED for RTS @ UCF BY MIKE BOROWCZAK
// PASSED INTO CHATGPT 5 OCT 2025 FOR CLEANUP/COMMENTS and
// to slow down timing so students can visually see task transitions.
#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_timer.h"
static SemaphoreHandle_t xMutex = NULL;
static volatile int shared_counter = 0; // Shared resource
static volatile int current_holder = 0; // 0 = none, 1 = Task1, 2 = Task2
// -----------------------------------------------------------------------------
// Utility: print current status every second (slower for visibility)
// -----------------------------------------------------------------------------
static void print_task(void *pvParameters)
{
(void) pvParameters;
while (1) {
int64_t time_ms = esp_timer_get_time() / 1000;
printf("[Monitor] Time=%" PRId64 " ms | Holder=%d | Counter=%d\n",
time_ms, current_holder, shared_counter);
vTaskDelay(pdMS_TO_TICKS(1000)); // print once per second
}
}
// -----------------------------------------------------------------------------
// Task 1: periodically enters the critical section and increments the counter
// -----------------------------------------------------------------------------
static void Task1(void *pvParameters)
{
(void) pvParameters;
while (1) {
// Wait before attempting to acquire mutex
vTaskDelay(pdMS_TO_TICKS(2000)); // 3 seconds idle
// Acquire mutex (blocks indefinitely if taken)
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
current_holder = 1;
printf("Task1: >>> ENTERING critical section <<<\n");
// Simulated slow work: increment shared resource
for (int i = 0; i < 3; i++) {
shared_counter++;
printf("Task1: working... counter=%d\n", shared_counter);
vTaskDelay(pdMS_TO_TICKS(1500)); // 1.5 seconds per step
}
printf("Task1: <<< LEAVING critical section >>>\n");
current_holder = 1;
xSemaphoreGive(xMutex); // Release mutex
}
}
}
// -----------------------------------------------------------------------------
// Task 2: also wants to access shared_counter (decrements)
// -----------------------------------------------------------------------------
static void Task2(void *pvParameters)
{
(void) pvParameters;
while (1) {
// Wait before attempting to acquire mutex
vTaskDelay(pdMS_TO_TICKS(2000)); // 2 seconds idle
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
current_holder = 2;
printf("Task2: >>> ENTERING critical section <<<\n");
// Simulated slow work: decrement shared resource
for (int i = 0; i < 3; i++) {
shared_counter--;
printf("Task2: working... counter=%d\n", shared_counter);
vTaskDelay(pdMS_TO_TICKS(2000)); // 2 seconds per step
}
printf("Task2: <<< LEAVING critical section >>>\n");
current_holder = 0;
xSemaphoreGive(xMutex);
}
}
}
// -----------------------------------------------------------------------------
// Entry point
// -----------------------------------------------------------------------------
void app_main(void)
{
// Create mutex
xMutex = xSemaphoreCreateMutex();
if (xMutex == NULL) {
printf("Failed to create mutex!\n");
return;
}
printf("Mutex created successfully\n");
// Launch monitor and tasks
// Monitor prints slowly so students can track ownership clearly.
xTaskCreate(print_task, "PrintTask", 2048, NULL, 1, NULL);
// Both tasks same priority to show natural alternation through mutex handoff
xTaskCreate(Task1, "Task1", 2048, NULL, 2, NULL);
xTaskCreate(Task2, "Task2", 2048, NULL, 2, NULL);
}
Loading
esp32-s2-devkitm-1
esp32-s2-devkitm-1