You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

嵌入式C99:如何解决多核CPU上的并发问题

多线程/多核场景下的C语言Data Race问题与解决方案

背景:C标准中的Data Race定义

C11标准(ISO/IEC 9899)新增了第5.1.2.4章《多线程执行与数据竞争》,并引入<stdatomic.h>头文件规范原子操作。

C2024标准(ISO/IEC 9899:2024)第5.1.2.5节第35段明确:

若程序执行中包含两个来自不同线程的冲突操作,且至少其中一个操作不是原子操作,且两者无先行关系,则存在data race。此类data race会导致未定义行为。

存在Data Race的示例代码

当生产者和消费者在不同执行线程中运行时,以下代码因无同步的共享变量访问会引发未定义行为:

Data data;
unsigned int ready = 0;  /* 0 表示未就绪;非0表示就绪 */

void producer(void)  /* 线程1调用 */
{
    initializeData();
    ready = 1;
}

void consumer(void)  /* 线程2调用 */
{        
    while(ready == 0)  /* Data Race 发生处 */
    { /* 等待就绪 */ }
    useData();
}

C11标准下的修复方案

将共享变量ready声明为原子类型,借助顺序一致性(sequential consistency)保证内存操作的可见性和顺序,修复未定义行为:

Data data;
atomic_uint ready = 0;  /* 0 表示未就绪;非0表示就绪 */

void producer(void)  /* 线程1调用 */
{
    initializeData();
    ready = 1;  /* 注:原示例此处为`ready = 0`,属于逻辑笔误,修正为符合业务语义的赋值 */
}

void consumer(void)  /* 线程2调用 */
{
    while(ready == 0)
    { /* 等待就绪 */ }
    useData();
}

C99标准未提及多线程或data race相关内容,但跨执行流对共享变量的无同步冲突访问仍会引发data race和未定义行为。


技术问题解答

1. 仅支持C99的嵌入式平台如何修复此类Data Race?

由于C99标准本身不提供多线程同步机制,需依赖编译器扩展和硬件特性:

  • 编译器内置原子操作:使用编译器提供的原子原语,比如GCC的__sync_bool_compare_and_swap__sync_fetch_and_add,或ARM编译器的__ldrex/__strex,保证对共享变量的读写操作是原子的。
  • 内存屏障指令:插入编译器层面的内存屏障(如GCC的__asm__ __volatile__ ("" ::: "memory"))阻止指令重排,同时根据硬件架构插入对应硬件内存屏障(如ARM的dmb、x86的mfence),确保内存操作的跨核心可见性。
  • 硬件级互斥锁:基于平台硬件指令实现自旋锁,用互斥锁包裹所有对共享变量的访问,保证同一时间只有一个执行流能操作共享数据。

2. 多核无线程场景下的并发访问是否会引发未定义行为?

是的,这种场景等同于不同执行线程的并发访问,会引发未定义行为。
不管是操作系统调度的线程,还是多核上直接运行的独立任务,只要是不同执行流对共享变量进行冲突操作(一个写操作 + 一个读/写操作),且没有同步机制,就符合C标准中data race的定义。C99标准的抽象机默认是单执行流,超出该范畴的并发访问本身属于标准未定义行为,而data race会进一步导致不可预测的程序行为。

3. 多核场景下是否存在更简便的解决方案?

有几种更简便的思路:

  • 利用硬件同步机制:很多嵌入式多核芯片提供核心间邮箱、全局信号量或中断控制等硬件同步原语,直接使用这些机制实现核心间同步,比纯软件实现更可靠高效。
  • 编译器扩展原子类型:即使不支持C11的<stdatomic.h>,多数主流编译器(如GCC、Clang)在C99模式下也支持_Atomic关键字扩展,直接声明共享变量为原子类型,编译器会自动生成对应的原子操作和内存屏障。
  • 避免共享状态:如果业务逻辑允许,将数据拆分到各核心的本地私有内存(如CPU的私有缓存区域),通过消息传递的方式交换数据,从根源上消除data race的可能。

内容的提问来源于stack exchange,提问作者Sonic78

火山引擎 最新活动