Bird
Raised Fist0
FreeRTOSprogramming~20 mins

Deadlock prevention patterns in FreeRTOS - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Deadlock Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this FreeRTOS task synchronization code?

Consider two tasks trying to acquire two mutexes in different orders. What output will the following code produce?

FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include <stdio.h>

SemaphoreHandle_t mutexA;
SemaphoreHandle_t mutexB;

void Task1(void *pvParameters) {
    if (xSemaphoreTake(mutexA, portMAX_DELAY) == pdTRUE) {
        vTaskDelay(10 / portTICK_PERIOD_MS);
        if (xSemaphoreTake(mutexB, portMAX_DELAY) == pdTRUE) {
            printf("Task1 acquired both mutexes\n");
            xSemaphoreGive(mutexB);
        }
        xSemaphoreGive(mutexA);
    }
    vTaskDelete(NULL);
}

void Task2(void *pvParameters) {
    if (xSemaphoreTake(mutexB, portMAX_DELAY) == pdTRUE) {
        vTaskDelay(10 / portTICK_PERIOD_MS);
        if (xSemaphoreTake(mutexA, portMAX_DELAY) == pdTRUE) {
            printf("Task2 acquired both mutexes\n");
            xSemaphoreGive(mutexA);
        }
        xSemaphoreGive(mutexB);
    }
    vTaskDelete(NULL);
}

int main(void) {
    mutexA = xSemaphoreCreateMutex();
    mutexB = xSemaphoreCreateMutex();
    xTaskCreate(Task1, "Task1", 1000, NULL, 1, NULL);
    xTaskCreate(Task2, "Task2", 1000, NULL, 1, NULL);
    vTaskStartScheduler();
    return 0;
}
A
Task1 acquired both mutexes
Task2 acquired both mutexes
BRuntime error due to mutex misuse
CDeadlock occurs, no output
D
Task2 acquired both mutexes
Task1 acquired both mutexes
Attempts:
2 left
💡 Hint

Think about what happens when two tasks wait for each other's mutex indefinitely.

🧠 Conceptual
intermediate
1:30remaining
Which deadlock prevention pattern is demonstrated by always acquiring mutexes in a fixed global order?

In FreeRTOS, to avoid deadlocks when multiple mutexes are needed, which pattern is best described by acquiring all mutexes in a consistent order?

ACircular Wait Prevention
BPreemption
CHold and Wait
DResource Ordering
Attempts:
2 left
💡 Hint

Think about how ordering resources can prevent cycles in resource allocation.

🔧 Debug
advanced
2:00remaining
Identify the cause of deadlock in this FreeRTOS code snippet

Examine the following code snippet. What causes the deadlock?

FreeRTOS
SemaphoreHandle_t mutex1 = xSemaphoreCreateMutex();
SemaphoreHandle_t mutex2 = xSemaphoreCreateMutex();

void TaskA(void *pvParameters) {
    xSemaphoreTake(mutex1, portMAX_DELAY);
    vTaskDelay(5 / portTICK_PERIOD_MS);
    xSemaphoreTake(mutex2, portMAX_DELAY);
    // Critical section
    xSemaphoreGive(mutex2);
    xSemaphoreGive(mutex1);
    vTaskDelete(NULL);
}

void TaskB(void *pvParameters) {
    xSemaphoreTake(mutex2, portMAX_DELAY);
    vTaskDelay(5 / portTICK_PERIOD_MS);
    xSemaphoreTake(mutex1, portMAX_DELAY);
    // Critical section
    xSemaphoreGive(mutex1);
    xSemaphoreGive(mutex2);
    vTaskDelete(NULL);
}
ATasks do not release mutexes after use
BTasks acquire mutexes in opposite order causing circular wait
CMutexes are not created before use
DvTaskDelay causes task starvation
Attempts:
2 left
💡 Hint

Look at the order in which each task takes the mutexes.

📝 Syntax
advanced
1:30remaining
Which option correctly implements a try-lock pattern to avoid deadlock in FreeRTOS?

To prevent deadlock, a task tries to take a mutex but gives up if not immediately available. Which code snippet correctly implements this try-lock?

FreeRTOS
SemaphoreHandle_t mutex = xSemaphoreCreateMutex();

void Task(void *pvParameters) {
    // Try to take mutex
    if (/* condition here */) {
        // Critical section
        xSemaphoreGive(mutex);
    } else {
        // Could not get mutex
    }
    vTaskDelete(NULL);
}
Aif (xSemaphoreTake(mutex, 0) == pdTRUE)
Bif (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
Cif (xSemaphoreTake(mutex, 10) == pdFALSE)
Dif (xSemaphoreGive(mutex) == pdTRUE)
Attempts:
2 left
💡 Hint

Try-lock means attempt to take mutex without waiting.

🚀 Application
expert
2:30remaining
How many items are in the queue after this deadlock prevention example runs?

Given a FreeRTOS system where tasks use a queue to signal resource availability and avoid deadlock, how many items remain in the queue after both tasks run?

FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <stdio.h>

QueueHandle_t resourceQueue;

void Task1(void *pvParameters) {
    int resource = 1;
    xQueueSend(resourceQueue, &resource, portMAX_DELAY);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    xQueueReceive(resourceQueue, &resource, portMAX_DELAY);
    printf("Task1 done\n");
    vTaskDelete(NULL);
}

void Task2(void *pvParameters) {
    int resource = 0;
    xQueueReceive(resourceQueue, &resource, portMAX_DELAY);
    xQueueSend(resourceQueue, &resource, portMAX_DELAY);
    printf("Task2 done\n");
    vTaskDelete(NULL);
}

int main(void) {
    resourceQueue = xQueueCreate(1, sizeof(int));
    xTaskCreate(Task1, "Task1", 1000, NULL, 1, NULL);
    xTaskCreate(Task2, "Task2", 1000, NULL, 1, NULL);
    vTaskStartScheduler();
    return 0;
}
A0
B1
C2
DDeadlock occurs, queue state unknown
Attempts:
2 left
💡 Hint

Consider how the queue is used to pass resource tokens between tasks.

Practice

(1/5)
1.

What is a common method to prevent deadlocks in FreeRTOS when multiple tasks need several mutexes?

Choose the best practice.

easy
A. Avoid using mutexes altogether
B. Allow tasks to take mutexes in any order
C. Use recursive mutexes without order
D. Always take mutexes in a fixed global order

Solution

  1. Step 1: Understand deadlock cause in FreeRTOS

    Deadlocks happen when tasks wait forever for mutexes held by each other in a cycle.
  2. Step 2: Apply fixed order mutex acquisition

    Taking mutexes always in the same order prevents circular wait, stopping deadlocks.
  3. Final Answer:

    Always take mutexes in a fixed global order -> Option D
  4. Quick Check:

    Fixed mutex order = deadlock prevention [OK]
Hint: Take mutexes always in the same order to avoid deadlocks [OK]
Common Mistakes:
  • Taking mutexes in random order
  • Ignoring priority inheritance
  • Using recursive mutexes incorrectly
2.

Which of the following is the correct way to create a mutex in FreeRTOS to help prevent deadlocks?

?
easy
A. xSemaphoreCreateMutex();
B. xSemaphoreCreateCounting(1, 1);
C. xQueueCreateMutex();
D. xSemaphoreCreateRecursiveMutex();

Solution

  1. Step 1: Identify FreeRTOS mutex creation functions

    FreeRTOS uses xSemaphoreCreateMutex() to create a standard mutex.
  2. Step 2: Differentiate from other semaphore types

    Counting semaphores and recursive mutexes serve different purposes; standard mutex is best for deadlock prevention.
  3. Final Answer:

    xSemaphoreCreateMutex(); -> Option A
  4. Quick Check:

    Standard mutex creation = xSemaphoreCreateMutex() [OK]
Hint: Use xSemaphoreCreateMutex() for standard mutex creation [OK]
Common Mistakes:
  • Confusing counting semaphore with mutex
  • Using recursive mutex without need
  • Trying to create mutex with queue functions
3.

Consider this FreeRTOS code snippet where two tasks try to take two mutexes in different orders:

Task1:
  xSemaphoreTake(mutexA, portMAX_DELAY);
  xSemaphoreTake(mutexB, portMAX_DELAY);

Task2:
  xSemaphoreTake(mutexB, portMAX_DELAY);
  xSemaphoreTake(mutexA, portMAX_DELAY);

What is the likely outcome?

medium
A. One task always fails to take mutex
B. Both tasks run without blocking
C. Deadlock occurs because tasks wait on each other's mutex
D. Tasks release mutexes immediately, no deadlock

Solution

  1. Step 1: Analyze mutex acquisition order

    Task1 takes mutexA then mutexB; Task2 takes mutexB then mutexA, creating circular wait.
  2. Step 2: Identify deadlock condition

    Each task waits for the other's mutex, causing deadlock with portMAX_DELAY blocking indefinitely.
  3. Final Answer:

    Deadlock occurs because tasks wait on each other's mutex -> Option C
  4. Quick Check:

    Opposite mutex order + infinite wait = deadlock [OK]
Hint: Opposite mutex order with infinite wait causes deadlock [OK]
Common Mistakes:
  • Assuming tasks run without blocking
  • Ignoring portMAX_DELAY effect
  • Thinking one task fails immediately
4.

Given this FreeRTOS code snippet, identify the problem that can cause deadlock:

void Task1(void *pvParameters) {
  xSemaphoreTake(mutex1, portMAX_DELAY);
  vTaskDelay(10);
  xSemaphoreTake(mutex2, portMAX_DELAY);
  // ...
  xSemaphoreGive(mutex2);
  xSemaphoreGive(mutex1);
}

void Task2(void *pvParameters) {
  xSemaphoreTake(mutex2, portMAX_DELAY);
  vTaskDelay(10);
  xSemaphoreTake(mutex1, portMAX_DELAY);
  // ...
  xSemaphoreGive(mutex1);
  xSemaphoreGive(mutex2);
}

What is the best fix to prevent deadlock?

medium
A. Remove all delays between mutex takes
B. Make both tasks take mutexes in the same order
C. Use recursive mutexes instead
D. Increase delay time to avoid overlap

Solution

  1. Step 1: Identify cause of deadlock

    Task1 takes mutex1 then mutex2; Task2 takes mutex2 then mutex1, causing circular wait and deadlock.
  2. Step 2: Apply fixed mutex order to both tasks

    Changing Task2 to take mutex1 then mutex2 avoids circular wait and prevents deadlock.
  3. Final Answer:

    Make both tasks take mutexes in the same order -> Option B
  4. Quick Check:

    Same mutex order = no deadlock [OK]
Hint: Fix mutex order in all tasks to the same sequence [OK]
Common Mistakes:
  • Removing delays does not fix deadlock
  • Using recursive mutexes won't solve order problem
  • Increasing delay time only delays deadlock
5.

You have three tasks that need to access three shared resources protected by mutexes: mutexX, mutexY, and mutexZ. To prevent deadlocks, which strategy is best?

  1. Task A needs mutexX and mutexY
  2. Task B needs mutexY and mutexZ
  3. Task C needs mutexX and mutexZ

Choose the best deadlock prevention pattern.

hard
A. Each task takes mutexes in alphabetical order: mutexX, mutexY, mutexZ
B. Each task takes mutexes in random order to improve speed
C. Use recursive mutexes for all mutexes
D. Tasks take mutexes only when all are free simultaneously

Solution

  1. Step 1: Analyze mutex requirements and potential deadlocks

    Tasks share mutexes in overlapping pairs, risking circular wait if order differs.
  2. Step 2: Apply fixed global order for mutex acquisition

    Taking mutexes always in alphabetical order (mutexX, mutexY, mutexZ) prevents circular wait and deadlocks.
  3. Final Answer:

    Each task takes mutexes in alphabetical order: mutexX, mutexY, mutexZ -> Option A
  4. Quick Check:

    Global fixed mutex order = deadlock prevention [OK]
Hint: Use global fixed order for all mutex acquisitions [OK]
Common Mistakes:
  • Taking mutexes randomly causes deadlocks
  • Recursive mutexes don't fix order issues
  • Waiting for all mutexes simultaneously is complex
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard