2013-07-08 4 views
2

저는 C++ for Windows에서 기본 데이터 유형에 대한 학습 연습으로 매우 간단한 원자 래퍼를 구현하고 있습니다. 할당 연산자를 구현하는 데 대한 몇 가지 간단한 질문이 있습니다. 원자 할당 연산자

// Simple assignment 
Atomic& Atomic::operator=(const Atomic& other) 
{ 
    mValue = other.mValue; 
    return *this; 
} 

// Interlocked assignment 
Atomic& Atomic::operator=(const Atomic& other) 
{ 
    _InterlockedExchange(&mValue, other.mValue); 
    return *this; 
} 

mValue가 올바른 타입이라고 가정하고 원자 클래스 멤버로 가지고, 아래 두 가지 구현 예를 고려한다.

  1. 스레드 안전성 할당 연산자에 대해 _InterlockedExchange이 필요합니까? 아니면 스레드 안전성을 보장 할만큼 간단한 구현입니까?
  2. 간단한 할당이 스레드로부터 안전하다면이 클래스에 대입 연산자를 구현해야 할 필요가 있습니까? 컴파일러 기본값으로 충분합니까?
  3. 단순 할당이 Windows에서 스레드로부터 안전하면 다른 플랫폼에서도 스레드로부터 안전합니까? 다른 플랫폼에서 스레드 안전을 보장하려면 _InterlockedExchange에 해당합니까? 상기 Atomic 오브젝트가 정렬되는 방법에 의존 mValue의 크기 및 배향에 의존

답변

6

경우mValue은 (폭 64 비트 CPU에서 대부분의 64 비트에서 32 비트 CPU 32 비트 폭 많아야하고) 프리미티브 타입, 사용자가 수동으로 데이터를 잘못 정렬하지 않는 경우, 메모리 읽기/쓰기가 원자적일 수 있음을 보장하는 x86 CPU (32 또는 64 비트 모드)에서 실행 중입니다.

이것은 자체적으로 컴파일러가 메모리 액세스를 재정렬하거나 완전히 최적화하지는 않지만 CPU는 이러한 크기의 데이터로 잘 정렬 된 읽기/쓰기가 절대적이지 않음을 보장합니다.

그러나 "스레드 안전성"은 코드가 사용되는 컨텍스트에 따라 달라 지므로 스레드 안전성이 아니라 원 자성에 대한 것입니다.

+0

이러한 조건이 사실이 아닐 경우,'_InterlockedExchange' (또는 다른 시스템에서 이에 상응하는 것)이 필요하거나 더 적합한 원자 함수가 있습니까? – Zeenobit

+1

보다 적합한 것은'std :: atomic'뿐입니다. –

+1

해당 조건이 참이 아닌 경우, * 조건 *에 따라 다릅니다. '_InterlockedExchange'는 마법이 아닙니다. 원자 적으로 보장되는 CPU 특정 명령어에 대한 래퍼입니다. 그러한 지시가 존재하지 않으면,'_InterlockedExchange'가 그것에 대해 할 수있는 것이 아무것도 없습니다 – jalf

2
  1. . 일반적으로 크기가 CPU 레지스터의 크기와 같고 적절히 정렬되면 쓰기는 원자 적입니다. (예 : 32 비트 CPU에서 32 비트 경계에 정렬 된 32 비트 데이터 유형은 원자 적으로 기록됩니다.이 시나리오에서는 64 비트 데이터 유형에 대한 원자 성이 보장되지 않습니다.)
  2. 컴파일러가 정확합니다 기본 구현은 mValue이 유일한 인스턴스 데이터 멤버라는 가정하에 "단순 할당"예제와 동일합니다.
  3. 보통 그렇습니다. 특정 운영 체제보다 CPU와 아키텍처의 기능이 더 많기 때문입니다. mValue이라는 글자가 아토믹하지 않은 경우 비슷한 구조가 필요합니다. (예를 들어, GCC documentation regarding built-in atomic operations 참조).
4

세 개의 개의 C++ 원자 유형이 처리하는 문제가 있습니다. 첫째, 읽기 또는 쓰기가 진행되는 동안 스레드 전환이 발생하여 데이터가 깨집니다. 이것은 "찢어짐"으로 알려져 있습니다. 둘째, 각 프로세서에는 자체 데이터 캐시가 있으며 한 스레드에 값을 쓰는 것이 반드시 다른 프로세서의 캐시에있는 값을 업데이트하는 것은 아닙니다. 이것은 "부실 데이터"입니다. 셋째, 컴파일러는 결과가 다양한 규칙을 위반하지 않으면 효율성을 향상시키기 위해 지침을 재정렬 할 수 있습니다. 쓰레드간에 데이터가 공유된다고 말하지 않으면 놀랄 일을 할 수 있습니다.

std::atomic (또는 원 자성을 보장하기위한 다양한 구현 별 메커니즘)을 사용하면 세 가지 문제가 모두 처리됩니다. 이유가 없으면을 사용하지 않아도됩니다. 라이브러리 및 컴파일러 작성자 거의 확실하게은 올바르게 작동하는 효율적인 코드를 생성하는 방법보다 잘 알고 있습니다.