Bất cứ ai có thể cho tôi biết liệu std :: atomic :: is_lock_free () không tĩnh cũng như constexpr? Có nó không tĩnh và / hoặc không phải là constexpr không có ý nghĩa đối với tôi.
Bất cứ ai có thể cho tôi biết liệu std :: atomic :: is_lock_free () không tĩnh cũng như constexpr? Có nó không tĩnh và / hoặc không phải là constexpr không có ý nghĩa đối với tôi.
Câu trả lời:
Như đã giải thích về cppreference :
Tất cả các loại nguyên tử ngoại trừ std :: atomic_flag có thể được thực hiện bằng cách sử dụng mutexes hoặc các hoạt động khóa khác, thay vì sử dụng các hướng dẫn CPU nguyên tử không khóa. Các loại nguyên tử đôi khi cũng được phép không có khóa, ví dụ: nếu chỉ các truy cập bộ nhớ được căn chỉnh là nguyên tử tự nhiên trên một kiến trúc nhất định, các đối tượng sai lệch cùng loại phải sử dụng khóa.
Tiêu chuẩn C ++ khuyến nghị (nhưng không yêu cầu) rằng các hoạt động nguyên tử không khóa cũng không có địa chỉ, nghĩa là phù hợp để liên lạc giữa các quá trình sử dụng bộ nhớ dùng chung.
Như được đề cập bởi nhiều người khác, std::is_always_lock_free
có thể là những gì bạn đang thực sự tìm kiếm.
Chỉnh sửa: Để làm rõ, các loại đối tượng C ++ có giá trị căn chỉnh giới hạn địa chỉ của các thể hiện của chúng chỉ ở bội số quyền hạn nhất định của hai ( [basic.align]
). Các giá trị căn chỉnh này được xác định theo thực hiện cho các loại cơ bản và không cần bằng kích thước của loại. Họ cũng có thể nghiêm ngặt hơn những gì phần cứng thực sự có thể hỗ trợ.
Ví dụ: x86 (hầu hết) hỗ trợ truy cập không được phân bổ. Tuy nhiên, bạn sẽ tìm thấy hầu hết các trình biên dịch có alignof(double) == sizeof(double) == 8
x86, vì các truy cập không được sắp xếp có một loạt các nhược điểm (tốc độ, bộ đệm, nguyên tử ...). Nhưng ví dụ #pragma pack(1) struct X { char a; double b; };
hoặc alignas(1) double x;
cho phép bạn có "không được phân bổ" double
. Vì vậy, khi cppreference nói về "truy cập bộ nhớ được căn chỉnh", có lẽ nó làm như vậy về mặt căn chỉnh tự nhiên của loại cho phần cứng, không sử dụng loại C ++ theo cách trái ngược với yêu cầu căn chỉnh của nó (sẽ là UB).
Dưới đây là thông tin thêm: Hiệu ứng thực tế của các truy cập không được phân bổ thành công trên x86 là gì?
Vui lòng kiểm tra các bình luận sâu sắc của @Peter Cordes bên dưới!
alignof(double)==4
. Nhưng std::atomic<double>
vẫn có alignof() = 8
thay vì kiểm tra căn chỉnh trong thời gian chạy. Sử dụng một cấu trúc đóng gói mà nguyên tử dưới căn chỉnh sẽ phá vỡ ABI và không được hỗ trợ. (GCC cho 32-bit x86 thích để cung cấp cho 8-byte đối tượng liên kết tự nhiên, nhưng quy tắc struct-đóng gói ghi đè lên đó và chỉ dựa trên alignof(T)
, ví dụ như trên i386 Hệ thống V. G ++ sử dụng để có một lỗi ở đâu atomic<int64_t>
bên trong một cấu trúc có thể không phải nguyên tử bởi vì nó chỉ là giả định. GCC (đối với C không phải C ++) vẫn có lỗi này!)
std::atomic_ref<double>
sẽ từ chối double
hoàn toàn liên kết dưới mức hoặc sẽ kiểm tra căn chỉnh trong thời gian chạy trên các nền tảng nơi nó hợp pháp double
và int64_t
không được căn chỉnh tự nhiên. (Bởi vì atomic_ref<T>
hoạt động trên một đối tượng được khai báo là đồng bằng T
và chỉ có căn chỉnh tối thiểu alignof(T)
mà không có cơ hội cho nó căn chỉnh thêm.)
_Atomic int64_t
khi được biên dịch với dòng điện gcc -m32
. Dù sao, quan điểm của tôi là các trình biên dịch thực sự không hỗ trợ các nguyên tử được liên kết dưới mức và không thực hiện kiểm tra thời gian chạy (chưa?), Vì vậy #pragma pack
hoặc __attribute__((packed))
sẽ chỉ dẫn đến phi nguyên tử; các đối tượng vẫn sẽ báo cáo rằng chúng là lock_free
.
is_lock_free()
việc cho phép các triển khai hoạt động khác với cách thực hiện hiện tại; với kiểm tra thời gian chạy dựa trên căn chỉnh thực tế để sử dụng các hướng dẫn nguyên tử được hỗ trợ bởi CTNH hoặc sử dụng khóa.
Bạn có thể sử dụng std::is_always_lock_free
is_lock_free
phụ thuộc vào hệ thống thực tế và không thể được xác định tại thời điểm biên dịch.
Giải thích có liên quan:
Các loại nguyên tử đôi khi cũng được phép không có khóa, ví dụ: nếu chỉ các truy cập bộ nhớ được căn chỉnh là nguyên tử tự nhiên trên một kiến trúc nhất định, các đối tượng sai lệch cùng loại phải sử dụng khóa.
std::numeric_limits<int>::max
phụ thuộc vào kiến trúc, nhưng là tĩnh và constexpr
. Tôi đoán không có gì sai trong câu trả lời, nhưng tôi không mua phần đầu tiên của lý luận
is_lock_free
là vô nghĩa trên trình biên dịch đó .
Tôi đã cài đặt Visual Studio 2019 trên Windows-PC của mình và devenv này cũng có trình biên dịch ARMv8. ARMv8 cho phép truy cập không được phân bổ, nhưng so sánh và hoán đổi, bổ sung bị khóa, v.v ... bắt buộc phải được căn chỉnh. Và cả tải thuần / cửa hàng thuần túy sử dụng ldp
hoặc stp
(cặp tải hoặc cặp thanh ghi 32 bit) chỉ được đảm bảo là nguyên tử khi chúng được căn chỉnh tự nhiên.
Vì vậy, tôi đã viết một chương trình nhỏ để kiểm tra những gì is_lock_free () trả về cho một con trỏ nguyên tử tùy ý. Vì vậy, đây là mã:
#include <atomic>
#include <cstddef>
using namespace std;
bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
return a64->is_lock_free();
}
Và đây là sự phân tách của isLockFreeAtomic
|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
movs r0,#1
bx lr
ENDP
Đây chỉ là returns true
, aka 1
.
Việc thực hiện này chọn sử dụng alignof( atomic<int64_t> ) == 8
để mọi thứ atomic<int64_t>
được căn chỉnh chính xác. Điều này tránh sự cần thiết phải kiểm tra căn chỉnh thời gian chạy trên mỗi tải và lưu trữ.
(Lưu ý của biên tập viên: điều này là phổ biến; hầu hết các triển khai C ++ ngoài đời thực đều hoạt động theo cách này. Đây là lý do tại sao std::is_always_lock_free
rất hữu ích: bởi vì nó thường đúng với các loại is_lock_free()
đã từng đúng.)
atomic<uint64_t>
vàalignof() == 8
vì vậy họ không phải kiểm tra căn chỉnh khi chạy. API cũ này cung cấp cho họ tùy chọn không làm như vậy, nhưng trên CTNH hiện tại, điều đó có ý nghĩa hơn nhiều chỉ cần yêu cầu căn chỉnh (nếu không thì UB, ví dụ như không nguyên tử). Ngay cả trong mã 32 bit, nơi int64_t
có thể chỉ có căn chỉnh 4 byte, atomic<int64_t>
yêu cầu 8 byte. Xem ý kiến của tôi về câu trả lời khác
alignof
giá trị cho loại cơ bản giống như căn chỉnh "tốt" của phần cứng, thì is_lock_free
sẽ luôn luôn true
(và như vậy is_always_lock_free
). Trình biên dịch của bạn ở đây thực hiện chính xác điều này. Nhưng API tồn tại để các trình biên dịch khác có thể làm những việc khác nhau.
alignof(std::atomic<double>) == 1
(vì vậy sẽ không có "quyền truy cập không được phân bổ" theo nghĩa C ++, do đó không có UB), ngay cả khi phần cứng chỉ có thể đảm bảo các hoạt động nguyên tử không khóadouble
s trên 4 hoặc Ranh giới 8 byte. Trình biên dịch sau đó sẽ phải sử dụng các khóa trong các trường hợp không được sắp xếp (và trả về giá trị boolean thích hợp từ is_lock_free
, tùy thuộc vào vị trí bộ nhớ của thể hiện đối tượng).
is_always_lock_free
không?