内存乱序的产生源于硬件和编译器的优化行为: 为了提升效率,编译器在代码生成阶段会重排序无依赖关系的指令,而CPU在执行阶段也可能乱序执行以最大化资源利用率;此外,多核处理器中的Cache缓存一致性机制也可能导致数据可见顺序的改变。 在单线程程序中,内存乱序通常不会影响结果,因为优化遵循数据依赖性原则,但多线程环境下,共享数据的访问顺序变化可能破坏逻辑,例如一个线程更新数据后,另一个线程可能因乱序而读取到未预期的值。
内存乱序主要分为编译期乱序和运行时乱序:
- 编译期乱序:编译器在优化时调整指令顺序,例如在Release模式下可能先存储标志变量再存储数据变量。
- 运行时乱序:CPU的乱序执行或缓存机制导致指令实际执行顺序与源码不同。 这种现象在不同硬件架构(如X86、ARM)和编译器上表现不一,因此多线程代码在特定平台测试正确,换环境后可能出错。
为解决内存乱序问题,可采用以下方法:
- 使用内存屏障:通过原子操作或内存屏障指令(如X86的mfence)强制指定内存操作顺序。
- 同步原语:锁、信号量等同步机制能隐式禁止乱序,但可能引入性能开销。
- 内存模型约束:在并发编程中,明确变量的内存可见性要求,例如使用volatile关键字或语言特定的原子类型。
对于STM32来说,内存屏障有DMB, DSB, ISB三种:
| DMB | Data Memory Barrier, 保证此指令之前的内存任务执行完毕,才会执行后续的内存任务。 |
| DSB | Data Synchronization Barrier, 保证此指令之前的内存任务执行完毕,之后才会执行后续指令。 |
| DMB | Instruction Synchronization Barrier, 保证所有已经完成的内存任务可以被后续指令识别。 |
我要赚赏金
