FreeRTOS入门教程(信号量的具体使用)

简介: FreeRTOS入门教程(信号量的具体使用)

前言

本篇文章来为大家讲解信号量的具体使用。

一、使用二值信号量完成同步

下面先举一个代码示例:

创建两个优先级相同的任务,这两个任务同时访问一个串口资源:

void Task1Function(void * param)
{
  int i;
  while (1)
  {
    printf("Task1\r\n");
  }
}
void Task2Function(void * param)
{
  while (1)
  {
    printf("Task2\r\n");
  }
}
xTaskCreate(Task1Function, "Task1", 100, NULL, 1, NULL);
xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);

运行结果:

通过运行结果可以看出两个任务的打印信息交错在了一起,这就是同时访问共享资源带来的问题,这里我们可以使用二值信号量来解决这个问题。

void Task1Function(void * param)
{
  while (1)
  {
    if (xSemaphoreTake(xSem, portMAX_DELAY) == pdTRUE)
    {
      printf("Task1\r\n");
      xSemaphoreGive(xSem);
      vTaskDelay(1);
    }
    else
    {
      printf("Task1 xSemaphoreTake is err\r\n"); 
    }
  }
}
void Task2Function(void * param)
{
  while (1)
  {
    if (xSemaphoreTake(xSem, portMAX_DELAY) == pdTRUE)
    {
      printf("Task2\r\n");
      xSemaphoreGive(xSem);
      vTaskDelay(1);
    }
    else
    {
      printf("Task2 xSemaphoreTake is err\r\n"); 
    }
  }
}
xSem = xSemaphoreCreateBinary();
xSemaphoreGive(xSem);
xTaskCreate(Task1Function, "Task1", 100, NULL, 1, NULL);
xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);

运行效果:

通过现象可以得知,使用信号量可以完成同步访问共享资源。

二、使用计数型信号量

#define BUFFER_SIZE 5
#define NUM_PRODUCERS 2
#define NUM_CONSUMERS 2
SemaphoreHandle_t bufferMutex;
SemaphoreHandle_t itemsCount;
int buffer[BUFFER_SIZE];
int itemCount = 0;
void producerTask(void *param) {
    int producerId = (int)param;
    while (1) {
        // 产生一个随机的数据
        int data = rand() % 100;
        // 尝试获取 itemsCount 计数型信号量,表示可用的缓冲区数量
        xSemaphoreTake(itemsCount, portMAX_DELAY);
        // 获取 bufferMutex 二值型信号量,保护缓冲区的访问
        xSemaphoreTake(bufferMutex, portMAX_DELAY);
        // 将数据放入缓冲区
        buffer[itemCount] = data;
        itemCount++;
        printf("Producer %d - Produced: %d, Total items: %d\n", producerId, data, itemCount);
        // 释放 bufferMutex 二值型信号量
        xSemaphoreGive(bufferMutex);
        // 通知消费者有新的数据可用
        xSemaphoreGive(itemsCount);
        // 延时一段时间
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
void consumerTask(void *param) {
    int consumerId = (int)param;
    while (1) {
        // 尝试获取 itemsCount 计数型信号量,表示可用的缓冲区数量
        xSemaphoreTake(itemsCount, portMAX_DELAY);
        // 获取 bufferMutex 二值型信号量,保护缓冲区的访问
        xSemaphoreTake(bufferMutex, portMAX_DELAY);
        // 从缓冲区获取数据
        int data = buffer[itemCount - 1];
        itemCount--;
        printf("Consumer %d - Consumed: %d, Total items: %d\n", consumerId, data, itemCount);
        // 释放 bufferMutex 二值型信号量
        xSemaphoreGive(bufferMutex);
        // 通知生产者有一个额外的缓冲区可用
        xSemaphoreGive(itemsCount);
        // 延时一段时间
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}
int main() {
    // 创建 bufferMutex 二值型信号量
    bufferMutex = xSemaphoreCreateMutex();
    // 创建 itemsCount 计数型信号量,初始值为 BUFFER_SIZE
    itemsCount = xSemaphoreCreateCounting(BUFFER_SIZE, BUFFER_SIZE);
    // 创建生产者任务
    for (int i = 0; i < NUM_PRODUCERS; i++) {
        xTaskCreate(producerTask, "Producer", configMINIMAL_STACK_SIZE, (void *)i, tskIDLE_PRIORITY + 1, NULL);
    }
    // 创建消费者任务
    for (int i = 0; i < NUM_CONSUMERS; i++) {
        xTaskCreate(consumerTask, "Consumer", configMINIMAL_STACK_SIZE, (void *)i, tskIDLE_PRIORITY + 2, NULL);
    }
    // 启动调度器
    vTaskStartScheduler();
    // 如果一切正常,下面的代码不应该执行到
    while (1) {
    }
    return 0;
}

使用二值型信号量 bufferMutex 来保护对缓冲区的访问,以防止多个任务同时访问引发竞争条件。使用计数型信号量 itemsCount 表示可用的缓冲区数量。当生产者将数据放入缓冲区时,会获取 itemsCount 信号量,并在获取成功后释放之前的信号量,从而告知消费者有新的数据可用。相反地,当消费者从缓冲区中取出数据时,会获取 itemsCount 信号量,并在获取成功后释放之前的信号量,从而告知生产者有一个额外的缓冲区可用。

总结

本篇文章就讲解到这里,大家多做实验多巩固复习。


相关文章
|
7月前
|
传感器 调度 开发者
【Freertos基础入门】freertos任务的优先级
【Freertos基础入门】freertos任务的优先级
171 0
|
5月前
|
消息中间件 调度
FreeRTOS入门教程(任务状态)
FreeRTOS入门教程(任务状态)
78 0
|
1月前
|
API 调度
【FreeRTOS】信号量的使用
【FreeRTOS】信号量的使用
|
7月前
|
存储 消息中间件 API
FreeRTOS入门教程(堆和栈)
FreeRTOS入门教程(堆和栈)
207 0
|
5月前
|
存储
FreeRTOS深入教程(信号量源码分析)
FreeRTOS深入教程(信号量源码分析)
73 0
|
5月前
|
算法 调度
FreeRTOS入门教程(互斥锁的概念和函数使用)
FreeRTOS入门教程(互斥锁的概念和函数使用)
92 0
|
5月前
|
消息中间件 算法 调度
FreeRTOS入门教程(同步与互斥)
FreeRTOS入门教程(同步与互斥)
98 0
|
5月前
|
数据采集 API 数据处理
FreeRTOS入门教程(软件定时器)
FreeRTOS入门教程(软件定时器)
56 0
|
5月前
|
存储 安全
FreeRTOS入门教程(队列的概念及相关函数介绍)
FreeRTOS入门教程(队列的概念及相关函数介绍)
48 0
|
7月前
【Freertos基础入门】深入浅出freertos互斥量
【Freertos基础入门】深入浅出freertos互斥量