You are here

Использование уведомлений в качестве бинарных семафоров

Source: https://www.freertos.org/RTOS_Task_Notification_As_Binary_Semaphore.html

Перевод может содержать ошибки. Читайте первоисточник.


[Task Notifications - Уведомления]

RTOS Task Notifications Used As Light Weight Binary Semaphores - Использование уведомлений в качестве бинарных семафоров

Разблокировка задачи с помощью уведомления на 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, &amp;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() завершился по таймауту. */
    }
}

Похожие страницы:

Hobby's category: