这篇文章记录FreeRTOS的互斥信号量的知识,希望我的分享对你有所帮助!
目录
[二、 创建互斥信号量](#二、 创建互斥信号量)
一、FreeRTOS互斥信号量简介
FreeRTOS的互斥信号量是一种特殊的信号量,用于保护共享资源,防止多个任务同时访问。它确保一次只有一个任务可以获取信号量,从而避免资源冲突。互斥信号量在使用时可以阻塞其他请求的任务,直到资源可用。
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中。在互斥访问中互斥信号量相当于一个钥匙,当任务想要使用资源的时候就必须先获得这个钥匙,当使用完资源以后就必须归还这个钥匙,这样其他的任务就可以拿着这个钥匙去使用资源。互斥信号量使用和二值信号量相同的API操作函数,所以互斥信号量也可以设置阻塞时间,不同于二值信号量的是互斥信号量具有优先级继承的特性。 当一个互斥信号量正在被一个低优先级的任务使用,而此时有个高优先级的任务也尝试获取这个互斥信号量的话就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级继承尽可能的降低了高优先级任务处于阻塞态的时间,并且****将已经出现的"优先级翻转"的影响降到最低。
优先级继承并不能完全的消除优先级翻转,它只是尽可能的降低优先级翻转带来的影响。硬实时应用应该在设计之初就要避免优先级翻转的发生。互斥信号量不能用于中断服务函数中,原因如下:互斥信号量有优先级继承的机制,所以****只能用在任务中,不能用于中断服务函数。
中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
二、 创建互斥信号量
1、创建互斥量的函数
(1)、动态创建互斥量的函数
FreeRTOS动态创建互斥量的函数是xSemaphoreCreateMutex()
函数的原型如下:
SemaphoreHandle_t xSemaphoreCreateMutex(void);
使用示例:
**Step1:**创建互斥信号量
SemaphoreHandle_t xMutex;
xMutex = xSemaphoreCreateMutex();
**Step2:**获取互斥信号量
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 访问共享资源
// 释放互斥信号量
xSemaphoreGive(xMutex);
}
**Step3:**释放互斥信号量
释放时使用
xSemaphoreGive(xMutex)
。
这里需要注意:
- 确保在不再需要互斥信号量时使用
vSemaphoreDelete(xMutex)
释放它。- 使用互斥信号量时,要注意嵌套获取和释放的情况,避免死锁。
用法示例:
如何在 FreeRTOS 中使用互斥量来保护共享资源。我们将创建两个任务,它们会同时访问和修改一个共享计数器。通过互斥量来确保对该计数器的安全访问。
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
// 定义共享资源
volatile int sharedCounter = 0;
// 定义互斥量句柄
SemaphoreHandle_t xMutex;
void vTask1(void *pvParameters) {
for (int i = 0; i < 5; i++) {
// 请求互斥量
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 临界区:安全地修改共享计数器
sharedCounter++;
printf("Task 1 incremented counter to %d\n", sharedCounter);
// 释放互斥量
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(100)); // 模拟处理时间
}
vTaskDelete(NULL);
}
void vTask2(void *pvParameters) {
for (int i = 0; i < 5; i++) {
// 请求互斥量
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 临界区:安全地修改共享计数器
sharedCounter += 2;
printf("Task 2 incremented counter to %d\n", sharedCounter);
// 释放互斥量
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(150)); // 模拟处理时间
}
vTaskDelete(NULL);
}
int main(void) {
// 创建互斥量
xMutex = xSemaphoreCreateMutex();
if (xMutex != NULL) {
// 创建任务
xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
}
// 如果一切正常,这里不会被执行
for (;;);
return 0;
}
共享资源:
sharedCounter
是一个全局变量,表示共享的计数器。由于它可能被多个任务同时访问,因此定义为volatile
。互斥量创建:
在
main()
函数中,通过xSemaphoreCreateMutex()
创建一个互斥量,用于保护对sharedCounter
的访问。任务实现:
vTask1
每次增加计数器 1,并打印当前值。vTask2
每次增加计数器 2,并打印当前值。每个任务在进入临界区时请求互斥量,并在操作完成后释放互斥量。任务调度:
在
main()
中创建两个任务并启动调度器,系统将开始运行这两个任务。
运行该程序时,你会看到任务交替地输出其对计数器的增值结果:
Task 1 incremented counter to 1
Task 2 incremented counter to 3
Task 1 incremented counter to 4
Task 2 incremented counter to 6
...每个任务在增加计数器时都确保了数据的一致性,因为它们在访问共享资源时使用了互斥量。这是多任务编程中保护共享资源的常见模式。
(2)、静态创建互斥量的函数
在 FreeRTOS 中,可以使用静态分配的方式创建互斥量,以便减少动态内存分配的需求。静态创建互斥量通常涉及以下步骤:
- 定义一个
StaticSemaphore_t
类型的变量。- 使用
xSemaphoreCreateMutexStatic()
函数来创建互斥量。
xSemaphoreCreateMutexStatic()
:
- 功能: 创建一个静态互斥量。
- 参数 :
pxMutexBuffer
: 一个指向StaticSemaphore_t
的指针,用于存储互斥量的控制数据。- 返回值 : 返回互斥量的句柄,如果创建失败则返回
NULL
。
下面是一个简单的 FreeRTOS 示例,演示如何静态创建互斥量并在两个任务中使用它。
1、定义资源:
StaticSemaphore_t xMutexBuffer
: 用于存储互斥量的静态控制信息。SemaphoreHandle_t xMutex
: 保存互斥量的句柄。2、任务函数:
vTaskFunction
: 这是两个任务的主体,每个任务尝试获取互斥量后进行处理,处理完毕后释放互斥量。3、主函数:
- 调用
xSemaphoreCreateMutexStatic
创建互斥量,将控制结构传入。这个函数不需要动态内存分配。- 使用
xTaskCreate
创建两个任务,分别执行同一个任务函数。4、调度器启动:
- 调用
vTaskStartScheduler()
启动 FreeRTOS 调度器,任务开始运行。
三、结语
关于FreeRTOS的互斥信号量的知识就分享到此了,希望我的分享对你有所帮助!