Bird
Raised Fist0
FreeRTOSprogramming~10 mins

xTaskNotifyGive() as lightweight semaphore in FreeRTOS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - xTaskNotifyGive() as lightweight semaphore
Task A: Calls xTaskNotifyGive(TaskB)
↓
Task B: Waits on ulTaskNotifyTake()
↓
Notification count increments
↓
Task B unblocks and continues
↓
Task B processes resource
↓
Task B loops back to wait for next notification
Task A sends a notification to Task B using xTaskNotifyGive(), incrementing a count. Task B waits with ulTaskNotifyTake() and unblocks when notified, acting like a lightweight semaphore.
Execution Sample
FreeRTOS
void TaskA(void *pvParameters) {
  for(;;) {
    xTaskNotifyGive(TaskBHandle);
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

void TaskB(void *pvParameters) {
  for(;;) {
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    // process resource
  }
}
Task A notifies Task B every second; Task B waits for notification and processes resource when notified.
Execution Table
StepActionTask B Notify CountTask B ulTaskNotifyTake() ReturnTask B StateOutput
1Task B starts and calls ulTaskNotifyTake(pdTRUE, portMAX_DELAY)0Blocks (waits)BlockedNo output
2Task A calls xTaskNotifyGive(TaskBHandle)1Still blockedBlockedNo output
3Task B unblocks, ulTaskNotifyTake() returns 10 (cleared)Returns 1RunningProcesses resource
4Task B loops and calls ulTaskNotifyTake() again0Blocks (waits)BlockedNo output
5Task A calls xTaskNotifyGive(TaskBHandle) again1Still blockedBlockedNo output
6Task B unblocks, ulTaskNotifyTake() returns 10 (cleared)Returns 1RunningProcesses resource
7Task B loops and calls ulTaskNotifyTake() again0Blocks (waits)BlockedNo output
ExitNo more notifications sent0Blocks indefinitelyBlockedWaiting forever
💡 Task B blocks indefinitely waiting for notification because Task A stops sending notifications.
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 5After Step 6Final
Task B Notify Count010100
Task B ulTaskNotifyTake() ReturnN/ABlocked1Blocked1Blocked
Task B StateBlockedBlockedRunningBlockedRunningBlocked
Key Moments - 3 Insights
Why does Task B block on ulTaskNotifyTake() even though Task A called xTaskNotifyGive()?
Task B blocks initially because no notification was sent yet (Step 1). After Task A calls xTaskNotifyGive() (Step 2), the notification count increments but Task B is still blocked until it unblocks (Step 3).
What happens to the notification count after ulTaskNotifyTake() returns?
The notification count is cleared to zero after ulTaskNotifyTake() returns (Step 3 and Step 6), ensuring the semaphore behavior.
Can multiple notifications accumulate if Task A calls xTaskNotifyGive() multiple times before Task B calls ulTaskNotifyTake()?
Yes, the notification count increments with each xTaskNotifyGive() call, allowing Task B to unblock multiple times without missing notifications, acting like a counting semaphore.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the Task B Notify Count after Step 2?
A0
B1
C2
DBlocked
💡 Hint
Check the 'Task B Notify Count' column at Step 2 in the execution_table.
At which step does Task B unblock and ulTaskNotifyTake() return 1 for the first time?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Look at the 'Task B ulTaskNotifyTake() Return' and 'Task B State' columns in the execution_table.
If Task A stops calling xTaskNotifyGive(), what happens to Task B's state after Step 7?
ABlocked indefinitely
BReady but not running
CRunning
DTerminated
💡 Hint
Refer to the 'Task B State' and 'Exit' row in the execution_table.
Concept Snapshot
xTaskNotifyGive() increments a task's notification count.
ulTaskNotifyTake() waits and clears this count.
Together, they act as a lightweight semaphore.
Task B blocks until notified by Task A.
Notification count allows multiple signals.
Useful for simple task synchronization.
Full Transcript
This visual trace shows how xTaskNotifyGive() and ulTaskNotifyTake() work together as a lightweight semaphore in FreeRTOS. Task A calls xTaskNotifyGive() to notify Task B, incrementing a notification count. Task B waits on ulTaskNotifyTake(), which blocks until the count is positive. When notified, ulTaskNotifyTake() returns and clears the count, allowing Task B to proceed. This mechanism allows Task B to block and unblock efficiently, synchronizing tasks without heavy semaphore overhead. The execution table tracks notification counts, task states, and function returns step-by-step, clarifying how notifications accumulate and are consumed.

Practice

(1/5)
1. What is the primary purpose of xTaskNotifyGive() in FreeRTOS?
easy
A. To send a simple signal from one task to another as a lightweight semaphore
B. To create a new task in the system
C. To delete a task permanently
D. To allocate memory dynamically

Solution

  1. Step 1: Understand the function role

    xTaskNotifyGive() is designed to send a notification signal from one task to another.
  2. Step 2: Compare with other options

    Creating or deleting tasks and memory allocation are unrelated to xTaskNotifyGive().
  3. Final Answer:

    To send a simple signal from one task to another as a lightweight semaphore -> Option A
  4. Quick Check:

    Signal sending = To send a simple signal from one task to another as a lightweight semaphore [OK]
Hint: Remember: xTaskNotifyGive() signals tasks like a lightweight semaphore [OK]
Common Mistakes:
  • Confusing it with task creation or deletion functions
  • Thinking it manages memory
  • Assuming it blocks tasks directly
2. Which of the following is the correct syntax to send a notification using xTaskNotifyGive() to a task handle named xTaskHandle?
easy
A. xTaskNotifyGive(xTaskHandle, 1);
B. xTaskNotifyGive(&xTaskHandle);
C. xTaskNotifyGive(xTaskHandle);
D. xTaskNotifyGive();

Solution

  1. Step 1: Recall function signature

    xTaskNotifyGive() takes a task handle as a parameter, not a pointer or extra arguments.
  2. Step 2: Check each option

    xTaskNotifyGive(xTaskHandle); correctly passes the task handle. xTaskNotifyGive(&xTaskHandle); passes address (wrong), C adds an extra argument (wrong), D has no argument (wrong).
  3. Final Answer:

    xTaskNotifyGive(xTaskHandle); -> Option C
  4. Quick Check:

    Correct syntax = xTaskNotifyGive(xTaskHandle); [OK]
Hint: Pass the task handle directly without extra arguments [OK]
Common Mistakes:
  • Passing pointer to task handle instead of handle itself
  • Adding extra parameters
  • Calling without any argument
3. Consider the following code snippet:
void Task1(void *pvParameters) {
    // Wait for notification
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    // Continue after notification
    printf("Task1 resumed\n");
}

void Task2(void *pvParameters) {
    // Notify Task1
    xTaskNotifyGive(Task1Handle);
}
What will be printed when Task2 calls xTaskNotifyGive()?
medium
A. Task2 resumes instead of Task1
B. Task1 resumed
C. Syntax error at compile time
D. No output, Task1 blocks forever

Solution

  1. Step 1: Understand notification flow

    Task1 waits for a notification with ulTaskNotifyTake(). When Task2 calls xTaskNotifyGive(), it sends the notification.
  2. Step 2: Effect of notification

    The notification unblocks Task1, so it prints "Task1 resumed".
  3. Final Answer:

    Task1 resumed -> Option B
  4. Quick Check:

    Notification received = Task1 prints [OK]
Hint: xTaskNotifyGive() wakes waiting task to continue [OK]
Common Mistakes:
  • Assuming Task1 never resumes
  • Confusing which task prints output
  • Thinking code causes compile error
4. Identify the error in this code snippet using xTaskNotifyGive():
void TaskA(void *pvParameters) {
    ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
    printf("TaskA running\n");
}

void TaskB(void *pvParameters) {
    xTaskNotifyGive(&TaskAHandle);
}
medium
A. Passing address of task handle instead of task handle to xTaskNotifyGive()
B. Using pdFALSE in ulTaskNotifyTake() causes immediate return
C. Missing delay in TaskB before notify
D. printf statement is incorrect syntax

Solution

  1. Step 1: Check parameter passed to xTaskNotifyGive()

    The function expects a task handle, but &TaskAHandle passes its address, which is incorrect.
  2. Step 2: Validate other parts

    Using pdFALSE is valid to clear notification count, no syntax error in printf, and delay is optional.
  3. Final Answer:

    Passing address of task handle instead of task handle to xTaskNotifyGive() -> Option A
  4. Quick Check:

    Correct parameter type needed = Passing address of task handle instead of task handle to xTaskNotifyGive() [OK]
Hint: Pass task handle directly, not its address [OK]
Common Mistakes:
  • Passing pointer to handle instead of handle
  • Misunderstanding pdFALSE effect
  • Assuming printf syntax error
5. You want to use xTaskNotifyGive() as a lightweight semaphore to synchronize two tasks: Producer and Consumer. The Consumer waits for the notification before processing data. Which sequence correctly implements this synchronization?
hard
A. Producer calls ulTaskNotifyTake(pdTRUE, portMAX_DELAY);, Consumer calls xTaskNotifyGive(ProducerHandle);
B. Consumer calls xTaskNotifyGive() and Producer calls ulTaskNotifyTake()
C. Both tasks call xTaskNotifyGive() simultaneously without waiting
D. Consumer calls ulTaskNotifyTake(pdTRUE, portMAX_DELAY); to wait, Producer calls xTaskNotifyGive(ConsumerHandle); to signal

Solution

  1. Step 1: Identify roles of tasks

    The Consumer should wait for a signal before processing, so it uses ulTaskNotifyTake() to block until notified.
  2. Step 2: Producer signals Consumer

    The Producer sends the notification using xTaskNotifyGive() with the Consumer's task handle.
  3. Final Answer:

    Consumer calls ulTaskNotifyTake(pdTRUE, portMAX_DELAY); to wait, Producer calls xTaskNotifyGive(ConsumerHandle); to signal -> Option D
  4. Quick Check:

    Wait then signal = Consumer calls ulTaskNotifyTake(pdTRUE, portMAX_DELAY); to wait, Producer calls xTaskNotifyGive(ConsumerHandle); to signal [OK]
Hint: Consumer waits, Producer signals with xTaskNotifyGive() [OK]
Common Mistakes:
  • Reversing roles of Producer and Consumer
  • Both tasks signaling without waiting
  • Using wrong task handles in calls
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