前提:我正在使用甚至没有C ++ 11(带有std::atomic<int>
)的ARM嵌入式(几乎是裸机)环境,因此请避免回答“ 仅使用标准C ++”std::atomic<int>
”:我不能。
这个AtomicInt的ARM 实现正确吗?(假设ARM体系结构是ARMv7-A)
您看到一些同步问题吗?是否volatile
需要/有用?
// File: atomic_int.h
#ifndef ATOMIC_INT_H_
#define ATOMIC_INT_H_
#include <stdint.h>
class AtomicInt
{
public:
AtomicInt(int32_t init = 0) : atom(init) { }
~AtomicInt() {}
int32_t add(int32_t value); // Implement 'add' method in platform-specific file
int32_t sub(int32_t value) { return add(-value); }
int32_t inc(void) { return add(1); }
int32_t dec(void) { return add(-1); }
private:
volatile int32_t atom;
};
#endif
// File: arm/atomic_int.cpp
#include "atomic_int.h"
int32_t AtomicInt::add(int32_t value)
{
int32_t res, prev, tmp;
asm volatile(
"try: ldrex %1, [%3]\n" // prev = atom;
" add %0, %1, %4\n" // res = prev + value;
" strex %2, %0, [%3]\n" // tmp = outcome(atom = res); // may fail
" teq %2, #0\n" // if (tmp)
" bne try" // goto try; /* add failed: someone else modified atom -> retry */
: "=&r" (res), "=&r" (prev), "=&r" (tmp), "+mo" (atom) // output (atom is both in-out)
: "r" (value) // input
: "cc"); // clobbers (condition code register [CPSR] changed)
return prev; // safe return (local variable cannot be changed by other execution contexts)
}
另外,我正在尝试实现一些代码重用,这就是为什么我只隔离了一个要在特定于平台的代码中实现的基本功能(add()
method arm/atomic_int.cpp
)的原因。
是atomic_int.h
真正便携,因为它是在不同的平台/体系结构/编译器?这种方法可行吗?(可行的意思是,每个平台通过仅实施add()
方法)。
这是相同功能的相应ARM GCC 8.3.1实现。显然,唯一真正的区别是dmb
之前和之后的存在。就我而言,他们真的需要吗?为什么?您是否有我AtomicInt
(没有dmb
)失败的例子?
更新:修复了实现,删除get()
了解决原子性和对齐问题的方法。现在,add()
行为就像一个标准fetchAndAdd()
。
您正在使用哪个版本的手臂架构?armv-7?
—
迈克·范·戴克
这没有解决问题,但是包含两个连续下划线(
—
皮特·贝克尔,
__ATOMIC_INT_H_
)的名称以及以下划线后跟大写字母开头的名称保留给实现使用。不要在代码中使用它们。
atomic
最好不要使用成员名称来避免与混淆std::atomic
,尽管它提出了一个问题,为什么无论如何都不会使用它。
添加了ARM体系结构,重命名了
—
gentooise
__ATOMIC_INT_H_
标识符。
volatile
C ++中的关键字表示不要通过变量进行优化。因此get()
方法从中受益。虽然,总的来说,volatile将在C ++中逐渐消失。如果您的系统无法内置同步32位数据,那么您别无选择,只能使用互斥锁-至少是自旋锁。