3. 共享资源与竞态条件

好,咱们进入第三章。这一章要聊的东西,说白了就是多核编程里最让人头疼的问题——共享资源竞态条件

我在TC2xx上做项目那会儿,第一次遇到竞态条件,debug了整整两天。最后发现就是一个全局变量被两个核同时写了。嗯,从那以后,我对共享资源就特别敏感。

3.1 什么是共享资源?

共享资源,顾名思义,就是能被多个任务或者多个核同时访问的东西。在TC2xx这种多核架构里,共享资源无处不在。

常见的共享资源包括:

  • 全局变量:比如一个用于统计的计数器,或者一个状态标志位
  • 外设寄存器:比如ADC的转换结果寄存器,或者CAN模块的发送缓冲区
  • 内存缓冲区:比如两个核之间传递数据的环形队列
  • 硬件描述符:比如DMA的描述符链表

你想想看,在单核系统里,这些资源天然就是安全的。因为同一时刻只有一个任务在跑。但到了多核环境,情况就完全不一样了。

核心观点:在TC2xx中,CPU0、CPU1、CPU2共享同一套外设和大部分内存空间。这意味着,任何一个核都可能在任何时刻访问同一个地址。

3.2 竞态条件——那个让你头疼的家伙

竞态条件,英文叫Race Condition。我习惯叫它「抢跑问题」。

什么叫竞态条件?简单说就是:多个执行单元同时访问共享资源,而最终结果取决于它们执行的先后顺序。这个顺序是不确定的,所以结果也是不确定的。

举个例子,你就能明白了:

// 假设这是一个全局计数器,两个核都在用
volatile uint32_t shared_counter = 0;

// Core 0 执行
shared_counter++;

// Core 1 执行
shared_counter++;

表面上看,两个核各加一次,结果应该是2。但实际运行中,结果可能是1,也可能是2。

为什么会这样?

因为 shared_counter++ 在底层其实是三步操作:

  1. 从内存读取值到寄存器
  2. 在寄存器里加1
  3. 把结果写回内存

如果Core 0刚读完值,还没写回去,Core 1也来读。那Core 1读到的就是旧值。两个核都加1,最后写回去的都是1。结果就是1,而不是2。

注意:这种bug非常隐蔽。它不会每次都出现,可能跑一万次才出一次。我在项目中遇到过,产品在实验室测了三天没问题,一上产线就随机死机。最后定位到就是竞态条件。

3.3 为什么多核环境下必须同步?

这个问题其实可以换个角度问:如果不做同步,会发生什么?

我总结了三个最典型的后果:

后果 具体表现 严重程度
数据不一致 共享变量值错误,逻辑判断出错
外设状态混乱 两个核同时配置同一个外设寄存器,导致配置被覆盖 极高
死锁或活锁 资源被错误占用,系统卡死 致命

你想想看,在汽车电子里,如果因为竞态条件导致一个传感器数据读错了,那后果可能是灾难性的。所以TC2xx这种车规级芯片,对同步机制的要求非常严格。

3.4 共享资源的分类

我个人习惯把共享资源分成三类,这样处理起来思路更清晰:

  • 只读资源:比如查表用的常量数组。多个核同时读没问题,不需要同步。
  • 独占资源:比如某个外设的配置寄存器。同一时刻只能有一个核操作。
  • 读写资源:比如全局变量。读和写都可能冲突,需要保护。

我的建议:在设计阶段就把共享资源列个清单,标清楚每个资源的类型和访问权限。别等到代码写完了再回头找问题,那时候就晚了。

3.5 一个真实的例子

我记得在TC275的项目里,CPU0负责采集ADC数据,CPU1负责做控制算法。它们共享一个数据缓冲区。

最初的设计是这样的:

// 共享缓冲区
uint16_t adc_buffer[64];
volatile uint8_t buffer_ready = 0;

// CPU0:采集完成,置标志
adc_buffer[0] = ADC_RESULT;
buffer_ready = 1;

// CPU1:检测到标志,读取数据
if(buffer_ready) {
    process_data(adc_buffer[0]);
    buffer_ready = 0;
}

看起来没问题对吧?但实际跑起来,CPU1偶尔会读到错误数据。

原因就是:CPU0写buffer和写标志之间,CPU1可能已经读到标志了。CPU1读到标志为1,但buffer里的数据还没写完。这就是典型的竞态条件。

解决办法?嗯,我们后面会讲到。这里先留个悬念。

3.6 小结

这一章我们聊了:

  • 共享资源的定义和常见类型
  • 竞态条件的本质——执行顺序的不确定性
  • 为什么多核环境必须做同步
  • 共享资源的分类方法

说白了,多核编程的核心挑战就是管理好这些共享资源。你躲不开它,只能正面解决它。下一章,我们就来聊聊TC2xx提供了哪些同步机制。

嗯,做好准备,后面才是真正的硬核内容。