如何保证使用stdatomic读取最新值?

问题描述 投票:0回答:1

在双核嵌入式系统中,由于多种原因,core0 需要中断 core1。枚举与联合配对用于传递中断的原因和数据。代码是用C编写的。

#include <stdatomic.h>

typedef enum { // the interrupt reason, also indicates which member is valid in the union
  kData0,
  // ...
} InterruptId;

typedef struct {
  _Atomic InterruptId interruptId;
  union { // data associated with interruptId
    int data0;
    // ...
  };
} SharedMemory;

// core0
void InterruptCore1(); // write some registers in ARM GIC to interrupt core1
void PassData0ToCore1(SharedMemory *mem, int data0) {
  mem->data0 = data0;
  atomic_store_explicit(&mem->interruptId, kData0, memory_order_release);
  InterruptCore1();
}

// core1
void ProcessData0(int data0);
void OnCore0Interrupt(SharedMemory *mem) {
  InterruptId id =
      atomic_load_explicit(&mem->interruptId, memory_order_acquire);
  switch (id) {
  case kData0:
    ProcessData0(mem->data0);
    break;
  }
}

上面的代码似乎不正确,因为 core1 可能会看到过时的

interruptId
值。据我了解,释放-获取顺序并不能保证加载可以读取最新值。也许atomic_thread_fence就是这里的解决方案。

typedef struct {
  InterruptId interruptId;
  union {
    int data0;
    // ...
  };
} SharedMemory;

// core0
void InterruptCore1(); // write some registers in ARM GIC to interrupt core1
void PassData0ToCore1(SharedMemory *mem, int data0) {
  mem->data0 = data0;
  mem->interruptId = kData0;
  atomic_thread_fence(memory_order_release);
  InterruptCore1();
}

// core1
void ProcessData0(int data0);
void OnCore0Interrupt(SharedMemory *mem) {
  atomic_thread_fence(memory_order_acquire);
  InterruptId id = mem->interruptId;
  switch (id) {
  case kData0:
    ProcessData0(mem->data0);
    break;
  }
}

atomic_thread_fence
的发布版本和获取版本都编译为
dmb ish
,这在机器级别似乎是正确的。但后来我读了C++版本的
atomic_thread_fence
,发现它也需要使用原子变量,并且只有当load真正读取到释放的值时同步才有效。

这是否意味着第二个解决方案与第一个解决方案具有相同的问题(core1 可能读取过时的值)?如何保证core1能读取到最新的值?非常感谢。

c++ c arm atomic memory-barriers
1个回答
0
投票

据我了解,释放-获取顺序并不能保证加载可以读取最新值。

所有内存顺序保证所有线程看到“最新”写入所有原子对象。差异源于您在其他对象中可以看到的状态,即对其他对象的写入是否可以围绕原子读取或写入重新排序。

© www.soinside.com 2019 - 2024. All rights reserved.