Предпосылка: я работаю со встроенной (почти голой) средой ARM, где у меня даже нет C ++ 11 (с std::atomic<int>
), поэтому, пожалуйста, избегайте ответов типа ", просто используйтестандартный C ++ std::atomic<int>
": Я не могу .
Является ли эта реализация ARM AtomicInt правильной? (предположим, что архитектура 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()
метод внутри arm/atomic_int.cpp
).
Является ли atomic_int.h
действительно переносимым , как на разных платформах / архитектурах / компиляторах? Является ли этот подход осуществимым ? (С осуществимым я имею в виду выполнимым для каждой платформы, чтобы гарантировать атомарность путем реализации только add()
метода ).
здесь является соответствующимARM GCC 8.3.1 реализация той же функции. Видимо, единственная реальная разница - это наличие dmb
до и после. Они действительно нужны в моем случае? Почему? У вас есть пример, когда мой AtomicInt
(без dmb
) не работает?
ОБНОВЛЕНИЕ: исправлена реализация, удален get()
метод для решения проблем атомарности и выравнивания. Теперь add()
ведет себя как стандартный fetchAndAdd()
.