Consider two tasks: TaskA and TaskB. TaskA calls xTaskNotifyGive(TaskBHandle); and TaskB waits using ulTaskNotifyTake(pdTRUE, portMAX_DELAY);. What will TaskB receive?
void TaskA(void *pvParameters) {
// Notify TaskB
xTaskNotifyGive(TaskBHandle);
vTaskDelay(pdMS_TO_TICKS(1000));
}
void TaskB(void *pvParameters) {
// Wait for notification
uint32_t count = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
printf("Notification count: %lu\n", count);
vTaskDelete(NULL);
}Think about what xTaskNotifyGive() does to the notification value and how ulTaskNotifyTake() reads it.
xTaskNotifyGive() increments the notification value by 1. ulTaskNotifyTake(pdTRUE, portMAX_DELAY) blocks until the notification value is non-zero, then returns the value and resets it to zero. So TaskB receives 1.
In FreeRTOS, how does xTaskNotifyGive() function as a lightweight semaphore?
Think about what happens to the task notification value when xTaskNotifyGive() is called.
xTaskNotifyGive() increments the notification value of a task, which can be used to signal that a resource is available, similar to giving a semaphore.
TaskA calls xTaskNotifyGive(TaskBHandle); twice quickly. TaskB calls ulTaskNotifyTake(pdTRUE, 1000); once. TaskB never proceeds. Why?
void TaskA(void *pvParameters) {
xTaskNotifyGive(TaskBHandle);
xTaskNotifyGive(TaskBHandle);
vTaskDelete(NULL);
}
void TaskB(void *pvParameters) {
uint32_t count = ulTaskNotifyTake(pdTRUE, 1000);
if(count == 0) {
printf("Timeout waiting for notification\n");
} else {
printf("Received notification count: %lu\n", count);
}
vTaskDelete(NULL);
}Consider how many notifications TaskB consumes with one call to ulTaskNotifyTake().
ulTaskNotifyTake(pdTRUE, timeout) returns the current notification count and resets it to zero. If TaskA calls xTaskNotifyGive() twice before TaskB calls ulTaskNotifyTake(), the count will be 2. But TaskB only calls ulTaskNotifyTake() once, so it consumes both notifications at once. The code should not block forever; if it does, likely TaskB is not running or the timeout is too short.
Choose the code snippet that correctly uses xTaskNotifyGive() and ulTaskNotifyTake() to synchronize two tasks.
Check the parameters of ulTaskNotifyTake() and how xTaskNotifyGive() is called.
xTaskNotifyGive() takes only the task handle as parameter. ulTaskNotifyTake() takes a boolean to clear the notification value and a timeout. The correct usage is ulTaskNotifyTake(pdTRUE, portMAX_DELAY); to block until notified and clear the count.
If TaskA calls xTaskNotifyGive(TaskBHandle); 5 times quickly, and TaskB calls ulTaskNotifyTake(pdTRUE, portMAX_DELAY); once, what is the value returned by TaskB?
Think about how xTaskNotifyGive() increments the notification value and how ulTaskNotifyTake() returns it.
xTaskNotifyGive() increments the notification value each time it is called. If called 5 times before ulTaskNotifyTake(), the notification value is 5. The call to ulTaskNotifyTake(pdTRUE, portMAX_DELAY) returns 5 and resets the count to zero.