std :: atomic :: is_lock_free ()가 constexpr뿐만 아니라 정적이지 않은지 누구든지 말해 줄 수 있습니까? 비 정적 및 / 또는 비 constprpr로 갖는 것은 의미가 없습니다.
std :: atomic :: is_lock_free ()가 constexpr뿐만 아니라 정적이지 않은지 누구든지 말해 줄 수 있습니까? 비 정적 및 / 또는 비 constprpr로 갖는 것은 의미가 없습니다.
답변:
cppreference에 설명 된 대로 :
std :: atomic_flag를 제외한 모든 원자 유형은 잠금없는 원자 CPU 명령을 사용하는 대신 뮤텍스 또는 기타 잠금 작업을 사용하여 구현할 수 있습니다. 원자 유형은 때로는 잠금이없는 경우도 있습니다. 예를 들어, 지정된 아키텍처에서 정렬 된 메모리 액세스 만 자연스럽게 원자 성인 경우 동일한 유형의 정렬되지 않은 객체는 잠금을 사용해야합니다.
C ++ 표준은 잠금없는 원자 연산에도 주소가 없어야하며 공유 메모리를 사용하는 프로세스 간 통신에 적합하도록 권장하지만 필수는 아닙니다.
여러 사람들이 언급했듯이, std::is_always_lock_free
당신이 정말로 찾고있는 것일 수 있습니다.
편집 : 명확히하기 위해 C ++ 객체 유형에는 인스턴스 주소를 2의 거듭 제곱 ( [basic.align]
)으로 제한하는 정렬 값이 있습니다. 이러한 정렬 값은 기본 유형에 대해 구현 정의되며 유형의 크기와 같을 필요는 없습니다. 하드웨어가 실제로 지원할 수있는 것보다 더 엄격 할 수도 있습니다.
예를 들어 x86 (대부분)은 정렬되지 않은 액세스를 지원합니다. 그러나 alignof(double) == sizeof(double) == 8
정렬되지 않은 액세스에는 많은 단점 (속도, 캐싱, 원 자성)이 있기 때문에 x86 용 컴파일러는 대부분 있습니다. 그러나 예를 들어 #pragma pack(1) struct X { char a; double b; };
또는 alignas(1) double x;
당신이 "정렬되지 않은"을 가질 수 있습니다 double
. 따라서 cppreference가 "정렬 된 메모리 액세스"에 대해 이야기 할 때, C ++ 유형을 사용하여 정렬 요구 사항 (UB)과 상반되는 방식으로 사용하지 않고 하드웨어에 대한 유형의 자연스러운 정렬과 관련하여 그렇게합니다.
자세한 정보는 다음과 같습니다 . x86에서 성공적으로 정렬되지 않은 액세스가 실제로 미치는 영향은 무엇입니까?
아래 @Peter Cordes 의 통찰력있는 의견을 확인하십시오 !
alignof(double)==4
. 그러나 std::atomic<double>
여전히 alignof() = 8
런타임에 정렬을 확인하는 대신에 있습니다. 원자를 언더 정렬하는 팩형 구조체를 사용하면 ABI가 중단되고 지원되지 않습니다. (32 비트 x86 용 GCC는 8 바이트 객체에 자연스럽게 정렬하는 것을 선호하지만, 구조체 패키징 규칙은이를 무시하고 alignof(T)
i386 시스템 V 와 같은 경우에만 기반합니다 . G ++ atomic<int64_t>
는 구조체 내부가 원자가 아닐 수 있는 버그 가있었습니다. GCC (C ++이 아닌 C의 경우)에는 여전히이 버그가 있습니다!
std::atomic_ref<double>
하면 double
완전히 정렬되지 않은 것을 거부 하거나 런타임에 정렬이 평범 double
하고 int64_t
자연스럽게 적합하지 않은 플랫폼에서 정렬을 검사합니다 . ( atomic_ref<T>
일반으로 선언 된 객체에서 작동 하기 때문에 추가 정렬을 할 수있는 기회없이 T
최소 정렬 만 alignof(T)
가능합니다.)
_Atomic int64_t
gcc -m32
#pragma pack
__attribute__((packed))
lock_free
is_lock_free()
하는 것입니다 수 있도록 구현은 현재 사람이 실제로 수행 방식과 다르게 작동; HW 지원 원자 명령어를 사용하거나 잠금을 사용하기 위해 실제 정렬을 기반으로 런타임 검사를합니다.
사용할 수 있습니다 std::is_always_lock_free
is_lock_free
실제 시스템에 따라 다르며 컴파일 타임에 확인할 수 없습니다.
관련 설명 :
원자 유형은 때로는 잠금이없는 경우도 있습니다. 예를 들어, 지정된 아키텍처에서 정렬 된 메모리 액세스 만 자연스럽게 원자 성인 경우 동일한 유형의 정렬되지 않은 객체는 잠금을 사용해야합니다.
std::numeric_limits<int>::max
아키텍처에 따라 다르지만 정적이며 정적 constexpr
입니다. 나는이 질문에 대해 아무것도 잘못이있는 것 같아요,하지만 난 추론의 첫 번째 부분 구입 해달라고
is_lock_free
입니다. 그것은 단지 그 컴파일러에서 의미가 없다는 것을 의미합니다 .
Windows-PC에 Visual Studio 2019를 설치했으며이 devenv에는 ARMv8 컴파일러도 있습니다. ARMv8은 정렬되지 않은 액세스를 허용하지만 비교 및 스왑, 잠금 추가 등은 정렬되도록 요구됩니다. 또한 ldp
또는 stp
(32 비트 레지스터의로드 쌍 또는 저장소 쌍)을 사용하는 순수로드 / 순수 저장소 는 자연적으로 정렬 될 때 원 자성 만 보장됩니다.
그래서 임의의 원자 포인터에 대해 is_lock_free ()가 반환하는 것을 확인하는 작은 프로그램을 작성했습니다. 코드는 다음과 같습니다.
#include <atomic>
#include <cstddef>
using namespace std;
bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
return a64->is_lock_free();
}
그리고 이것은 isLockFreeAtomic의 분해입니다
|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
movs r0,#1
bx lr
ENDP
이것은 단지 returns true
일명 1
입니다.
이 구현은 alignof( atomic<int64_t> ) == 8
모든 atomic<int64_t>
것이 올바르게 정렬되도록 사용 하도록 선택합니다 . 따라서 모든로드 및 스토어에서 런타임 정렬 검사가 필요하지 않습니다.
(편집자 주 : 이것은 일반적입니다. 대부분의 실제 C ++ 구현은 이런 방식으로 작동합니다. 이것이 std::is_always_lock_free
매우 유용한 이유 입니다 . 일반적으로 항상 유형이 사실이기 때문 is_lock_free()
입니다.)
atomic<uint64_t>
하고 alignof() == 8
그래서 그들은 런타임에 정렬을 체크 할 필요가 없습니다. 이 오래된 API는 그렇지 않은 옵션을 제공하지만 현재 HW에서는 정렬 (그렇지 않으면 UB, 예를 들어 비원 자성)을 요구하는 것이 훨씬 더 합리적입니다. int64_t
4 바이트 만 정렬 할 수 있는 32 비트 코드에서도 atomic<int64_t>
8 바이트가 필요합니다. 다른 답변에 대한 내 의견
alignof
근본적인 형 하드웨어의 "좋은"정렬과 같은 가치를, 다음 is_lock_free
항상있을 것이다 true
(그래서 것이다 is_always_lock_free
). 여기서 컴파일러는 정확하게 이것을 수행합니다. 그러나 API는 존재하므로 다른 컴파일러는 다른 작업을 수행 할 수 있습니다.
alignof(std::atomic<double>) == 1
하드웨어가 double
4에 대한 잠금없는 원자 연산 만 보장 할 수 있더라도 (예 : C ++ 의미에서 "정렬되지 않은 액세스"가 없으므로 UB가 없음) 언어에는 아무것도 없습니다. 8 바이트 경계. 그러면 컴파일러는 정렬되지 않은 경우 잠금을 사용해야합니다 (그리고 is_lock_free
객체 인스턴스의 메모리 위치에 따라 적절한 부울 값을에서 반환 ).
is_always_lock_free
계십니까?