0
0
FreeRTOSprogramming~10 mins

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

Choose your learning style9 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.