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 信号量,并在获取成功后释放之前的信号量,从而告知生产者有一个额外的缓冲区可用。

总结

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


相关文章
|
C语言 C++
boost库asio编译及配置
boost库asio编译及配置
904 0
|
存储 安全 API
基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)
基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
1268 19
|
Java 数据安全/隐私保护
Fortify——安装并修改报告语言为中文
Fortify——安装并修改报告语言为中文
2229 0
Fortify——安装并修改报告语言为中文
|
Linux Windows
Windows、Mac、Linux解决端口被占用的问题
Windows、Mac、Linux解决端口被占用的问题
477 1
|
算法 调度
FreeRTOS入门教程(互斥锁的概念和函数使用)
FreeRTOS入门教程(互斥锁的概念和函数使用)
1581 0
51单片机的延时函数快速生成技巧
51单片机的延时函数快速生成技巧
1075 1
|
编解码
STM32CubeMX FreeRTOS u8g2图片菜单制作
STM32CubeMX FreeRTOS u8g2图片菜单制作
1254 8
|
存储 小程序
【FreeRTOS】队列的使用
【FreeRTOS】队列的使用
626 0

热门文章

最新文章