Программирование ARM FreeRTOS: xSemaphoreTake, xSemaphoreGive Mon, June 24 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

FreeRTOS: xSemaphoreTake, xSemaphoreGive Печать
Добавил(а) microsin   

Семафор это стандартный объект RTOS, предназначенный для синхронизации между задачами. Он может использоваться для защиты общего ресурса (например памяти FLASH) от попыток одновременного доступа из нескольких задач.

Совет: во многих сценариях использование прямого оповещения задачи является более быстрым и эффективным способом по сравнению с применением семафора.

Для захвата и освобождения семафора используются макросы xSemaphoreTake и xSemaphoreGive, определение этих макросов находится в заголовочном файле semphr.h. Перед тем, как можно будет использовать макросы, семафор для них должен быть создан вызовом xSemaphoreCreateBinary(), или xSemaphoreCreateMutex(), или xSemaphoreCreateCounting().

xSemaphoreTake. Это макрос, который предназначен для захвата семафора.

xSemaphoreTake (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

Макрос xSemaphoreTake нельзя вызывать из кода обработчика прерывания (ISR). Для этой цели существует специальный макрос xQueueReceiveFromISR(), хотя стиль программирования с использованием xQueueReceiveFromISR нельзя считать допустимым. Семафоры используют очереди в качестве нижележащего механизма синхронизации, поэтому функции синхронизации во многом совместимы (что вносит некоторую путаницу).

Параметры xSemaphoreTake:

xSemaphore дескриптор семафора, который должен быть захвачен задачей.

xTicksToWait время в тиках системы, в течение которого осуществляется блокировка в ожидании освобождения семафора. Для указания реального времени времени в микросекундах может использоваться макрос portTICK_PERIOD_MS. Если указать нулевое время блокировки, то макрос xSemaphoreTake может использоваться для опроса семафора.

Если опция INCLUDE_vTaskSuspend конфигурации FreeRTOS установлена в '1', то указание время блокировки portMAX_DELAY приведет к бесконечной блокировке задачи на семафоре (без таймаута).

Возвращаемое значение: pdTRUE, если семафор был успешно захвачен, и pdFALSE если истек таймаут xTicksToWait, но семафор не стал доступен.

Пример использования:

SemaphoreHandle_t xSemaphore = NULL;
 
/* Задача, которая создает семафор. */
void vATask (void *pvParameters)
{
   /* Создание семафора для защиты общего ресурса. Поскольку мы используем в качестве
      Поскольку мы создаем семафор как средство реализации взаимоисключающего
      доступа к ресурсу для задач (mutual exclusion), то создаем мьютекс вместо
      двоичного семафора. */
   xSemaphore = xSemaphoreCreateMutex();
}
 
/* Задача, которая использует семафор. */
void vAnotherTask (void *pvParameters)
{
   /* ... Тут какие-то другие действия ... */
 
   if (xSemaphore != NULL)
   {
      /* Проверка, можем ли мы захватить семафор. Если семафор недоступен, то будем
         ждать его освобождения в течение 10 тиков системы. */
      if (xSemaphoreTake(xSemaphore, (TickType_t)10) == pdTRUE)
      {
         /* Мы можем захватить семафор, и можем нормально распоряжаться
            общим ресурсом. */
 
         /* ... Манипуляции с общим ресурсом ... */
 
         /* Мы завершили работу с общим ресурсом. Освободим семафор, чтобы сигнализировать
            о доступности общего ресурса для других задач. */
         xSemaphoreGive( xSemaphore );
      }
      else
      {
         /* Не получилось захватить семафор, и пока нельзя получить безопасный доступ
            к общему ресурсу. */
      }
   }
}

xSemaphoreGive. Макрос для публикации (освобождения) семафора.

xSemaphoreGive (SemaphoreHandle_t xSemaphore);

Этот макрос не должен использоваться в коде ISR, для этой цели используйте xSemaphoreGiveFromISR(). Также этот макрос не должен использоваться на семафорах, созданных вызовом xSemaphoreCreateRecursiveMutex().

Параметры xSemaphoreGive:

xSemaphore дескриптор семафора, который должен быть освобожден. Этот дескриптор был возвращен ранее при создании семафора.

Возвращаемое значение: pdTRUE, если семафор был освобожден. pdFALSE, если произошла ошибка. Реализация семафоров основана на очередях. Ошибка может произойти, если на очереди не осталось пространства для публикации сообщения - показывает, что семафор не был ранее корректно захвачен.

Пример использования:

SemaphoreHandle_t xSemaphore = NULL;
 
void vATask (void *pvParameters)
{
   // Создание семафора для защиты общего ресурса. Поскольку мы используем семафор
   // как средство взаимного исключения, то для его создания вызовем создание
   // мьютекса вместо двоичного семафора.
   xSemaphore = xSemaphoreCreateMutex();
 
   if (xSemaphore != NULL)
   {
      if (xSemaphoreGive(xSemaphore) != pdTRUE)
      {
         // Попытка освободить семафор, который не был предварительно "взят"!
      }
 
      // Попытка захвата семафора. Произойдет только проверка без блокировки,
      // если семафор пока недоступен.
      if (xSemaphoreTake(xSemaphore, (TickType_t)0))
      {
         // Теперь мы получили владение над семафором, и может пользоваться
         // общим ресурсом, который защищен этим семафором.
         // ...
         // Мы завершили доступ к общему ресурсу, и можем освободить семафор.
         if (xSemaphoreGive(xSemaphore) != pdTRUE)
         {
            // Неожиданная ошибка, потому что выше мы успешно взяли семафор.
         }
      }
   }
}

[Ссылки]

1. FreeRTOS xSemaphoreTake site:freertos.org.
2. FreeRTOS: семафоры со счетчиком и оповещения задач.
3. Semaphores API site:freertos.org.

 

Добавить комментарий


Защитный код
Обновить

Top of Page