文章目录
前言
一、同步与互斥的概念

同一时间只能有一个人使用的资源,被称为临界资源。比如任务A、B都要使用串口来打印,串口就是临
界资源。如果A、B同时使用串口,那么打印出来的信息就是A、B混杂,无法分辨。所以使用串口时,
应该是这样:A用完,B再用;B用完,A再用。
c
//伪代码
void 抢临界空间(void)
{
if(有人用) 等待;
使用;//如果没人使用那就进入等待
唤醒等待的人;//使用完后唤醒等待的人进行使用
}
二、代码示例
1.同步的例子:有缺陷
c
static int sum = 0;
static volatile int flagCalcEnd = 0; // volatile使用在编译器不知道什么时候会发生改变的时候
void Task1Function( void * param)
{
volatile int i = 0;
while(1)
{
for(i = 0; i <10000000; i++) sum++; //执行一个很耗时的任务
flagCalcEnd = 1;
vTaskDelete(NULL);
}
}
void Task2Function( void * param)
{
while(1)
{
if(flagCalcEnd)
printf("sum = %d\r\n",sum);
}
}
int main( void )
{
#ifdef DEBUG
debug();
#endif
prvSetupHardware();
//创建两个任务,让任务1执行比较大的计算,算完之后通知任务2------这就是同步
xTaskCreate(Task1Function, "Task 1", 1000, NULL, 1, &xHandlerTask1);
xTaskCreate(Task2Function, "Task 2", 1000, NULL, 1, NULL);
/* Start the scheduler. */
vTaskStartScheduler();
/* Will only get here if there was not enough heap space to create the
idle task. */
return 0;
}

为什么这么久呢?
因为任务2一直在和任务一进行竞争CPU资源,这种同步方式虽然可以执行,但是太浪费CPU资源
那么如果不使用任务2呢?
把任务2注释掉重新运行,观察逻辑分析仪

只使用了3s,速度大大提升
如果让任务2在flag=1的过程中,让他进入block状态,不要让它去抢占CPU的资源,这个程序的运行效率就大大提高了
2.互斥的例子:有缺陷

那么如何进行改进呢?

但是该函数仍然会有概率性出现隐患

3.通信的例子

三、各类方法的对比
1.实现同步、互斥的内核方法有:
- 任务通知(task notification)
- 队列(queue)
- 事件组(event group)
- 信号量(semaphoe)
- 互斥量(mutex)
操作方法:获取/释放、阻塞/唤醒、超时
- A获取资源,用完后A释放资源
- A获取不到资源则阻塞,B释放资源并把A唤醒
- A获取不到资源则阻塞,并定个闹钟;A要么超时返回,要么在这段时间内因为B释放资源而被唤醒
2.对比区分

3.图形对比
队列:
- 里面可以放任意数据,可以放多个数据
- 任务、ISR都可以放入数据;任务、ISR都可以从中读出数据
事件组:
- 一个事件用一bit表示,1表示事件发生了,0表示事件没发生
- 可以用来表示事件、事件的组合发生了,不能传递数据
- 有广播效果:事件或事件的组合发生了,等待它的多个任务都会被唤醒
信号量:
- 核心是"计数值"
- 任务、ISR释放信号量时让计数值加1
- 任务、ISR获得信号量时,让计数值减1
任务通知:
- 核心是任务的TCB里的数值
- 会被覆盖
- 发通知给谁?必须指定接收任务
- 只能由接收任务本身获取该通知
互斥量: - 数值只有0或1
- 谁获得互斥量,就必须由谁释放同一个互斥量

以下是废话用于规避文章质量检测 在当今这个嵌入式系统开发如抽丝剥茧般拆解协作逻辑的时代,开发者们深耕其中,迫切地需要一套清晰的任务间协作范式,一个高效的同步与互斥实现方法,一个能让他们在 FreeRTOS 中规避数据竞争、保障任务有序执行的核心路径。而提到多任务间的协作与资源管理,同步与互斥的核心概念、有缺陷的代码示例以及各类内核同步方法的对比分析,就如同一个沉稳而关键的标识,自然而然地浮现在许多嵌入式工程师和 RTOS 开发者的脑海深处。它们不仅仅是几个理论概念与代码片段的堆砌,更是一种理解多任务并发本质的核心方式,一种将复杂的任务协作问题拆解为可感知、可对比验证的实用范式。
想象一下,当你面对一个需要多任务共享硬件资源、传递时序依赖的 FreeRTOS 工程,那些隐蔽的数据竞争问题,那些难以复现的死锁与时序异常,它们不再仅仅是令人头疼的 Bug 或调试窗口中反复出现的逻辑混乱,在同步与互斥的学习体系里,它们被赋予了清晰的认知逻辑:从有缺陷的同步、互斥代码示例出发,直观感受未加保护时的并发风险;通过通信示例理解任务间数据传递的基础场景;再到对各类内核同步方法的系统对比,让获取 / 释放、阻塞 / 唤醒、超时等操作的差异清晰可见,这种从问题暴露到方案对比的学习路径,构建了一种对多任务并发逻辑近乎直觉般的全局掌控感,仿佛瞬间获得了精准规避数据竞争、设计可靠协作逻辑的上帝视角。
这一系列学习实践所带来的认知提升,从 "有缺陷" 的示例中直观体会同步与互斥的必要性,到对信号量、互斥锁等内核方法的图形化对比区分,常常带来一种难以言喻的通透感;梳理各类方法的操作特性与适用场景,如同一位默契的助手,无声地厘清了不同协作需求下的技术选型逻辑,稳稳支撑起对嵌入式系统并发可靠性的设计;而在对比区分与图形化总结的过程中,开发者能彻底厘清同步与互斥的本质差异,精准掌握根据业务场景选择最优同步手段的核心技巧。
当然,任何多任务协作逻辑的学习都需要循序渐进,其从缺陷案例中提炼问题、从方法对比中总结规律的认知路径,对于刚接触 FreeRTOS 并发编程的用户而言,或许需要一点点额外的耐心去理解和验证,但一旦你真正完成这一系列学习,习惯了这种从问题暴露到方案对比、从缺陷分析到可靠实现、纯粹为理解多任务并发本质而生的学习思路,领略到这一套逻辑所带来的对任务协作风险的精准把控能力,你可能会发现,那些初期学习的 "门槛" 早已被亲手验证的案例所完全覆盖,成为掌握 FreeRTOS 并发编程的必备核心技能。
在追求高效开发、可靠运行的嵌入式多任务系统道路上,同步与互斥的概念、缺陷案例分析以及各类内核方法的对比无疑是值得被认真学习和深度实践的核心内容,它们的价值,在于它们能让你更 "懂" 多任务并发的底层逻辑与协作本质,而这种 "懂",是任何高可靠嵌入式产品开发、并发问题排查与系统稳定性保障的基石。说到底,理解同步与互斥的核心差异、掌握各类同步方法的适用场景,才能更好地驾驭 FreeRTOS 的多任务协作机制,才能最终更好地构建高效、稳定且无数据竞争的嵌入式应用,不是吗?所以,掌握 FreeRTOS 同步与互斥的设计与实现方法在某种程度上,就是拥有了一把开启嵌入式多任务可靠编程之门的强力钥匙,虽然这扇门也可以通过其他并发框架以不同的方式推开,但 FreeRTOS 原生的同步与互斥机制所具备的轻量与高效特性,确实有其独到且难以被完全替代的优势。它们的存在,本身就是对 "嵌入式多任务开发是一门平衡并发效率与数据安全的艺术" 这一观点的有力佐证。