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_freecó 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) == 8x86, 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() = 8thay 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 doublehoà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 doublevà int64_tkhô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 Tvà 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_tkhi đượ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 packhoặ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>::maxphụ 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_freelà 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 ldphoặ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_freerấ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_tcó 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
                    alignofgiá 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_freekhông?