C语言从句柄到对象 (七) —— 给对象加把锁:RTOS 环境下的并发安全

前言: 在《抛弃 Malloc》一文中,我们设计了一个静态对象池:

Motor_Handle Motor_Create(void) {

for (int i = 0; i < MAX; i++) {

if (pool[i].is_allocated == 0) { // A

pool[i].is_allocated = 1; // B

return i;

}

}

}

这段代码在裸机(单线程)环境下是完美的。 但在 RTOS(多任务)环境下,它就是一个 "定时炸弹"

假设 任务 A 刚执行完语句 A(判断未占用),还没来得及执行 B(标记占用),就被高优先级的 任务 B 打断了。 任务 B 也执行了 Motor_Create,它发现该位置也是空的,于是占用了它,拿到了句柄 0。 任务 B 执行完,切回任务 A。任务 A 继续执行语句 B,也占用了位置 0,拿到了句柄 0

后果:两个任务拿到了同一个句柄,操作同一个内存块,系统逻辑彻底错乱。

这就是经典的 竞态条件 (Race Condition)


一、 保护资源分配:临界区 (Critical Section)

我们要保护的第一个地方,是 "分配资源" 的过程。 在扫描池子的时候,绝对不允许任何人打断。

1.1 改造 Create 函数

我们需要引入 RTOS 的 临界区保护(关中断或调度锁)。

// motor_driver.c

Motor_Handle Motor_Create(void) {

Motor_Handle h = MOTOR_INVALID_HANDLE;

// 【加锁】进入临界区 (关中断)

// 不同的 RTOS 写法不同,这里用伪代码

OS_ENTER_CRITICAL();

for (int i = 0; i < MAX_MOTORS; i++) {

if (motor_pool[i].is_allocated == 0) {

motor_pool[i].is_allocated = 1;

h = (Motor_Handle)i;

break; // 找到了,赶紧退出循环

}

}

// 【解锁】退出临界区 (开中断)

OS_EXIT_CRITICAL();

return h;

}

加上这两行代码,你的静态内存池就变成了 "线程安全 (Thread-Safe)" 的了。


二、 保护内部数据:对象锁 (Mutex)

仅仅保护分配是不够的。 假设任务 A 正在调用 Motor_SetSpeed 修改参数,刚改了一半(比如改了频率,还没改占空比),任务 B 插进来读取了状态。这时候任务 B 读到的就是 脏数据

我们需要给 每一个对象 配一把锁。

2.1 在结构体中引入互斥锁

// motor_driver.c (内部定义)

struct Motor_t {

uint8_t is_allocated;

// ... 业务数据 ...

// 【新增】每个对象一把互斥锁

OS_Mutex_t lock;

};

2.2 在 Create 时初始化锁

Motor_Handle Motor_Create(void) {

// ... 分配逻辑 ...

if (found) {

// 创建互斥锁

OS_Mutex_Create(&motor_pool[i].lock);

return i;

}

}

2.3 在 API 中自动加锁

这是架构设计的精髓:不要让用户去加锁,驱动要在内部自动处理。

int Motor_SetSpeed(Motor_Handle h, uint8_t speed) {

// 1. 校验句柄

if (h >= MAX_MOTORS || !motor_pool[h].is_allocated) return ERROR;

struct Motor_t *p = &motor_pool[h];

// 2. 【自动加锁】等待拿到锁,防止别人同时修改

OS_Mutex_Take(p->lock, TIMEOUT_FOREVER);

// 3. 修改数据 (临界区)

p->current_speed = speed;

HAL_PWM_Set(p->port, speed);

// 4. 【自动解锁】

OS_Mutex_Give(p->lock);

return SUCCESS;

}

三、 总结

通过引入 全局临界区 (保护池子)和 对象互斥锁 (保护个例),我们将一个"裸机驱动"升级为了 "工业级 RTOS 驱动"

  • 原则 1:资源分配(Create/Destroy)必须原子化。

  • 原则 2:对象状态读写必须互斥。

/*******************************************
* Description:
* 本文为作者《嵌入式开发基础与工程实践》系列文之一。
* 关注我即可订阅后续内容更新,采用异步推送机制。
* 转发本文可视为广播分发,有助于信息传播至更多节点。
*******************************************/

相关推荐
三万棵雪松2 小时前
【python-基础】
开发语言·python
先做个垃圾出来………2 小时前
2610.转换二维数组
开发语言·python
中國龍在廣州2 小时前
谈谈2025年人工智能现状及发展趋势分析
人工智能·深度学习·算法·自然语言处理·chatgpt·机器人·机器人学习
利刃大大2 小时前
【SpringBoot】validation参数校验 && JWT鉴权实现 && 加密/加盐
java·spring boot·jwt·加密
天下皆白_唯我独黑2 小时前
php -S 启动项目访问路由报错处理
开发语言·php
清水迎朝阳2 小时前
Qt 小白成长系列 1-- 官方 文本搜索示例解析
开发语言·qt
小北方城市网2 小时前
第 3 课:前后端全栈联动核心 —— 接口规范 + AJAX + 跨域解决(打通前后端壁垒)
java·大数据·网络·python
Joe_Blue_022 小时前
Matlab入门案例介绍—常用的运算符及优先级
开发语言·数据结构·matlab·matlab基础入门案例介绍
降临-max2 小时前
JavaWeb企业级开发---MySQL
java·开发语言·数据库·笔记·后端·mysql