Приміщення: я працюю із вбудованим у 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()
.
__ATOMIC_INT_H_
) та імена, які починаються з підкреслення, за яким йде велика літера, зарезервовані для використання реалізацією. Не використовуйте їх у своєму коді.
atomic
, мабуть, найкраще не використовувати, щоб уникнути плутанини std::atomic
, хоча воно ставить питання, чому ви б не використовували це ні в якому разі.
__ATOMIC_INT_H_
ідентифікатор.
volatile
ключове слово в C ++ означає, що не оптимізується за допомогою змінної. Тожget()
метод виграє від цього. Хоча, загалом, мінливі ось-ось будуть зображуватися в C ++. Якщо ваша система не може вбудовувати 32-бітні дані синхронізації, то у вас є мало іншого вибору, крім того, щоб використовувати мутекси - щонайменше.