Source: https://www.freertos.org/RTOS_Task_Notification_As_Binary_Semaphore.html
Перевод может содержать ошибки. Читайте первоисточник.
[Task Notifications - Уведомления]
Разблокировка задачи с помощью уведомления на 45% быстрее и требует меньше ОЗУ, чем разблокировка с помощью бинарного семафора. На этой странице приведены фрагменты кода, показывающие, как это может быть реализовано в приложении.
Бинарный семафор это семафор, который имеет максимальное значение 1, поэтому он и называется бинарным. Задача может только "взять" семафор, если он доступен, и семафор доступен только если его значение равно 1.
Когда уведомление используется вместо бинарного семафора, поле уведомления в задаче-получателе используется для размещения значения бинарного семафора, а функция API ulTaskNotifyTake() используется вместо функции API xSemaphoreTake(). При этом в вызове ulTaskNotifyTake() параметр xClearOnExit устанавливаем в значение pdTRUE, чтобы значение семафора обнулялось каждый раз, когда оно забирается - т.е. для эмуляции именно бинарного семафора.
Аналогично функции xTaskNotifyGive() и vTaskNotifyGiveFromISR() используются вместо функций xSemaphoreGive() и xSemaphoreGiveFromISR().
/*----------------------------------------------------------------------------*/ /* В этом примере реализована передача данных из функции в некий обобщённый драйвер периферии. Задача RTOS вызывает функцию передачи, затем ждёт в заблокированном состоянии (не потребляя процессорного времени), пока не получит уведомления о том, что передача завершена. Передача выполняется с использованием ПДП. Прерывание по окончанию пересылки с ПДП используется для уведомления задаче-отправителю. */ /* Сохраняем хэндлер задачи, которую необходимо информировать о завершении передачи. */ static TaskHandle_t xTaskToNotify = NULL; /* Функция передачи в драйвер периферии. */ void StartTransmission( uint8_t *pcData, size_t xDataLength )<br>{ /* В этом месте указатель xTaskToNotify должен иметь значение NULL, что указывает на то, что в данный момент нет передачи. Мьютекс может быть использован для контроля доступа к периферии, если это необходимо. */ configASSERT( xTaskToNotify == NULL ); /* Сохраняем хэндлер вызывающей задачи. */ xTaskToNotify = xTaskGetCurrentTaskHandle(); /* Запускаем передачу - прерывание будет вызвано, когда передача завершится. */ vStartTransmit( pcData, xDatalength ); } /*----------------------------------------------------------------------------*/ /* Прерывание по завершению передачи. */ void vTransmitEndISR( void ) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; /* В этом месте указатель xTaskToNotify должен иметь значение, отличное от NULL, что указывает на активность процесса передачи. */ configASSERT( xTaskToNotify != NULL ); /* Уведомляем задачу о завершении передачи. */ vTaskNotifyGiveFromISR( xTaskToNotify, &xHigherPriorityTaskWoken ); /* Нет никаких процессов передачи, поэтому и нет задач, которые нужно было бы уведомлять о завершении передачи. */ xTaskToNotify = NULL; /* Если xHigherPriorityTaskWoken теперь установлен в значене pdTRUE, то необходимо выполнить переключение контекста, чтобы возврат из прерывания произошёл к разблокированной задаче с наивысшим приоритетом. Макрос, используемый для этого, зависит от реализации RTOS для вашего процессора и может называться portEND_SWITCHING_ISR(). */ portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } /*----------------------------------------------------------------------------*/ /* Задача, которая инициировала передачу, далее переходит в заблокированное состояние (т.е. не использует процессорное время) для ожидания завершения передачи. */ void vAFunctionCalledFromATask( uint8_t ucDataToTransmit, size_t xDataLength ) { uint32_t ulNotificationValue; const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 200 ); /* Запуск переачи вызовом функции, которая приведена выше. */ StartTransmission( ucDataToTransmit, xDataLength ); /* Ждём уведомления о завершении передачи. Заметьте, что первый параметр задан pdTRUE, что вызывает сброс значения уведомления в 0, превращая уведомление в аналог бинарного, а не счётного семафора. */ ulNotificationValue = ulTaskNotifyTake( pdTRUE, xMaxBlockTime ); if( ulNotificationValue == 1 ) { /* Обнаружено завершение передачи. */ } else { /* Вызов функции ulTaskNotifyTake() завершился по таймауту. */ } }