Tiền đề: Tôi đang làm việc với môi trường nhúng ARM (gần như kim loại trần), nơi tôi thậm chí không có sẵn C ++ 11 (có std::atomic<int>
), vì vậy vui lòng tránh các câu trả lời như " chỉ sử dụng C ++ tiêu chuẩnstd::atomic<int>
": Tôi không thể .
Việc ARM triển khai AtomicInt này có đúng không? (giả sử kiến trúc ARM là ARMv7-A )
Bạn có thấy một số vấn đề đồng bộ hóa? Có volatile
cần thiết / hữu ích không?
// 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)
}
Ngoài ra, tôi đang cố gắng để đạt được một số tái sử dụng mã, đó là lý do tại sao tôi chỉ tách biệt một chức năng cơ bản để triển khai trong mã dành riêng cho nền tảng ( add()
phương thức bên trong arm/atomic_int.cpp
).
Có atomic_int.h
thực sự di động vì nó là trên các nền tảng / kiến trúc / trình biên dịch khác nhau? Cách tiếp cận này có khả thi không? (Với tính khả thi tôi có nghĩa là khả thi cho mọi nền tảng để đảm bảo tính nguyên tử bằng cách thực hiện chỉ add()
phương pháp ).
đây là triển khai ARM GCC 8.3.1 tương ứng có cùng chức năng. Rõ ràng, sự khác biệt thực sự duy nhất là sự hiện diện của dmb
trước và sau. Họ có thực sự cần thiết trong trường hợp của tôi? Tại sao? Bạn có một ví dụ mà tôi AtomicInt
(không dmb
) không thành công?
CẬP NHẬT: thực hiện cố định, get()
phương pháp loại bỏ để giải quyết các vấn đề nguyên tử và căn chỉnh. Bây giờ các add()
hành vi như một tiêu chuẩn fetchAndAdd()
.
__ATOMIC_INT_H_
) và các tên bắt đầu bằng dấu gạch dưới theo sau là chữ in hoa được dành riêng cho việc triển khai. Đừng sử dụng chúng trong mã của bạn.
atomic
có lẽ tốt nhất không được sử dụng để tránh nhầm lẫn std::atomic
, mặc dù nó đặt ra câu hỏi tại sao bạn sẽ không sử dụng nó trong mọi trường hợp.
__ATOMIC_INT_H_
định danh.
volatile
từ khóa trong C ++ có nghĩa là không tối ưu hóa thông qua biến. Vì vậy,get()
phương pháp được hưởng lợi từ nó. Mặc dù, nói chung, dễ bay hơi sắp cạn kiệt trong C ++. Nếu hệ thống của bạn không thể tích hợp đồng bộ hóa dữ liệu 32 bit, thì bạn có rất ít sự lựa chọn ngoài việc sử dụng mutexes - spinlock trong ít nhất.