互斥锁的概念
互斥锁(Mutex,全名Mutual Exclusion)是一种用于控制多个线程对共享资源访问的同步机制。在并发编程中,多个线程同时访问共享资源可能导致数据不一致性或竞态条件(Race Condition)。为了避免这种情况,可以使用互斥锁来确保在任意时刻只有一个线程能够访问共享资源。
互斥锁的基本原理是,当一个线程想要访问共享资源时,它必须先尝试获取互斥锁。如果该锁已经被其他线程持有,那么请求线程就会被阻塞,直到锁被释放。一旦线程成功获取了互斥锁,它就可以安全地访问共享资源,完成操作后再释放锁,以便其他线程可以继续访问。
在不同的编程语言和操作系统中,互斥锁的实现方式可能会有所不同,但基本的思想是一致的。使用互斥锁可以有效地防止多个线程同时修改共享数据,从而确保线程安全性。
需要注意的是,虽然互斥锁能够解决竞态条件问题,但过度使用锁可能导致性能问题,因为锁的获取和释放会引入额外的开销。因此,在设计并发程序时,需要谨慎考虑锁的使用,以在安全性和性能之间找到平衡。
FreeRTOS的互斥锁
FreeRTOS 是一款用于嵌入式系统的实时操作系统(RTOS)。FreeRTOS 提供了一些同步机制,其中包括用于保护共享资源的互斥锁。在 FreeRTOS 中,互斥锁称为二进制信号量,通过 Semaphore 数据结构实现。
以下是 FreeRTOS 中互斥锁的基本使用方法:
1. 引入头文件
在使用互斥锁之前,需要引入 FreeRTOS 的头文件。
#include "FreeRTOS.h"
#include "semphr.h"
2. 创建互斥锁
使用 xSemaphoreCreateMutex() 函数创建一个互斥锁。这个函数返回一个指向互斥锁的句柄。
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
3. 获取互斥锁(加锁)
在访问共享资源之前,需要获取互斥锁。使用 xSemaphoreTake() 函数来尝试获取锁。
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 访问共享资源的代码
// ...
}
portMAX_DELAY 表示无限等待,直到成功获取锁。
4. 释放互斥锁(解锁)
在访问共享资源后,需要释放互斥锁,以便其他任务可以获取锁。
xSemaphoreGive(xMutex);
通过调用 xSemaphoreGive() 来释放互斥锁。
在以上的代码片段中,xMutex 是互斥锁的句柄,xSemaphoreTake() 用于获取锁,xSemaphoreGive() 用于释放锁。在实时系统中,这样的互斥锁机制有助于确保共享资源的线程安全性。
请注意,FreeRTOS 还提供其他类型的信号量,如计数信号量,可以用于更灵活的同步操作。在使用 FreeRTOS 时,建议查阅官方文档和示例代码,以确保正确地使用互斥锁和其他同步机制。
STM32F103案例
创建一个互斥锁,然后有两个任务,每个任务都会尝试获取互斥锁,然后对共享资源进行访问。
请确保已经配置好 STM32CubeMX 和相关的开发环境,同时已经集成了 FreeRTOS。
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "stm32f1xx_hal.h"
// 互斥锁句柄
SemaphoreHandle_t xMutex;
// 共享资源
volatile uint32_t sharedResource = 0;
void Task1(void *pvParameters) {
while (1) {
// 尝试获取互斥锁
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 访问共享资源
sharedResource++;
// 释放互斥锁
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(1000)); // 任务延时1秒
}
}
void Task2(void *pvParameters) {
while (1) {
// 尝试获取互斥锁
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 访问共享资源
sharedResource--;
// 释放互斥锁
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(500)); // 任务延时500毫秒
}
}
int main(void) {
// 初始化 FreeRTOS
HAL_Init();
SystemClock_Config();
// 创建互斥锁
xMutex = xSemaphoreCreateMutex();
// 创建任务
xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
// 启动调度器
vTaskStartScheduler();
// 程序不应该执行到这里
while (1) {
}
}
在这个例子中,使用 xMutex 作为互斥锁的句柄,两个任务 Task1 和 Task2 分别尝试获取互斥锁,对共享资源进行读写,并在操作后释放互斥锁。 vTaskDelay 函数用于模拟任务的执行时间。
请注意,这只是一个简单的示例,实际的应用可能需要更多的复杂性和保护来确保线程安全。此外,确保在 STM32CubeMX 中正确配置 FreeRTOS,包括堆栈和任务优先级等。在实际应用中,你可能需要添加更多的任务和功能,以满足特定的需求。
关于CubeMX的配置请看我以前更新的博客