Двоичный семафор разблокировать после создания?

Попытка использовать двоичный семафор на плате обнаружения STM32F4 с FreeRTOS дает некоторые странные (даже неправильные) результаты.

Прежде всего, документация для FreeRTOS гласит:

SemaphoreHandle_t xSemaphoreCreateBinary (void);

Функция, которая создает двоичный семафор. Двоичные семафоры либо доступны, либо недоступны, следовательно, двоичные.

Семафор создается в "пустом" состоянии. Это означает, что семафор должен быть задан прежде, чем его можно будет получить (получить) с помощью функции xSemaphoreTake().

Это здорово, потому что в этом случае некоторые Thread1 ждут семафор, созданный ранее, пока он не разблокируется (Thread2 дает семафор), так что это звучит Отлично!!

Поэтому, начиная с платы обнаружения stm32f4, на которой выполняется FreeRTOS и приведенный ниже код, можно ожидать, что вызов osSemaphoreWait(myBinarySem01Handle,osWaitForever) будет блокировать поток, пока другой поток не разблокирует его с помощью osSemaphoreRelease, но он не работает. Похоже, что после создания семафора необходимо дважды вызвать osSemaphoreWait, чтобы он заработал.

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"

/* USER CODE BEGIN Includes */     
#include "gpio.h"
/* USER CODE END Includes */

/* Variables -----------------------------------------------------------------*/
osThreadId defaultTaskHandle;
osThreadId myTask02Handle;
osSemaphoreId myBinarySem01Handle;
osSemaphoreId myBinarySem02Handle;
osSemaphoreId myCountingSem01Handle;
osSemaphoreId myCountingSem02Handle;

/* USER CODE BEGIN Variables */

/* USER CODE END Variables */

/* Function prototypes -------------------------------------------------------*/
void StartDefaultTask(void const * argument);
void StartTask02(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

/* Hook prototypes */

/* Init FreeRTOS */

void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* Create the semaphores(s) */
  /* definition and creation of myBinarySem01 */
  osSemaphoreDef(myBinarySem01);
  myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);

  /* definition and creation of myBinarySem02 */
  osSemaphoreDef(myBinarySem02);
  myBinarySem02Handle = osSemaphoreCreate(osSemaphore(myBinarySem02), 1);

  /* definition and creation of myCountingSem01 */
  osSemaphoreDef(myCountingSem01);
  myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 2);

  /* definition and creation of myCountingSem02 */
  osSemaphoreDef(myCountingSem02);
  myCountingSem02Handle = osSemaphoreCreate(osSemaphore(myCountingSem02), 2);

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of myTask02 */
  osThreadDef(myTask02, StartTask02, osPriorityNormal, 0, 128);
  myTask02Handle = osThreadCreate(osThread(myTask02), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */
}

/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{

  HAL_GPIO_TogglePin(LD6_GPIO_Port,LD6_Pin);

  osSemaphoreWait(myBinarySem01Handle,osWaitForever);

  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LD6_GPIO_Port,LD6_Pin);
    osDelay(1000);
  }
  /* USER CODE END StartDefaultTask */
}

/* StartTask02 function */
void StartTask02(void const * argument)
{


    HAL_GPIO_TogglePin(LD5_GPIO_Port,LD5_Pin);
    osDelay(5000);
    osSemaphoreRelease(myBinarySem01Handle);


  /* USER CODE BEGIN StartTask02 */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LD5_GPIO_Port,LD5_Pin);
    osDelay(2000);
  }
  /* USER CODE END StartTask02 */
}

/* USER CODE BEGIN Application */

/* USER CODE END Application */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Так в чем же причина такого поведения? В документации четко сказано, что семпахор должен блокироваться после создания.

1 ответ

Чтение дополнительной документации выявило проблему, макрос vSemaphoreCreateBinary() имеет семантику, отличную от функции xSemaphoreCreateBinary ().

Макрос vSemaphoreCreateBinary() не блокируется при первом вызове xSemaphoreTake (), сильно отличается от xSemaphoreCreateBinary (), который блокирует при первом вызове xSemaphoreTake ().

http://www.freertos.org/xSemaphoreCreateBinary.html

http://www.freertos.org/a00121.html

Это происходит потому, что функция osSemaphoreCreate() вызывает функцию vSemaphoreCreateBinary() и, как сказано выше, эта функция создает непустой двоичный семафор.

Другие вопросы по тегам