สถานที่ตั้ง: ผมทำงานกับ ARM ฝังตัว (เกือบเปลือยโลหะ) สภาพแวดล้อมที่ฉันไม่ได้มี C ++ 11 (กับstd::atomic<int>
) ใช้ได้ดังนั้นโปรดหลีกเลี่ยงคำตอบเช่น " เพียงแค่ใช้มาตรฐาน 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()
เมธอดด้านใน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 บิตในตัวได้แสดงว่าคุณมีทางเลือกน้อย แต่ให้ใช้ mutexes - spinlock อย่างน้อยที่สุด