2012-05-10 4 views
3

기본 산술 연산은 스레드로부터 안전합니까?C#의 기본 산술 연산은 원자입니까

예를 들어, 다른 스레드에서 수정 될 전역 변수에 대해 ++ 작업이있는 경우 해당 스레드를 수정해야합니까?

void MyThread() 
{ 
    lock(lockerObj) 
    { 
     aGlobal++; 
    } 
} 
+4

이것은 배타적 인 산술 연산이 아닙니다 ... 변수에 대한 쓰기도 있습니다! 'a + a'는'a = a + a'와는 다른 것입니다. 'Interlocked.Increment' 또는 alikes를 사용해야합니다! –

답변

8

The spec

예를

void MyThread() // can have many running instances 
{ 
    aGlobal++; 
} 

를 들어

하거나해야한다 아주 잘 요약. 5.5 "변수 참조의 자성"

읽고 다음 데이터 유형 중 기록 원자이다 : BOOL, 숯, 바이트 sbyte, 짧은 USHORT, UINT, INT, 플로트, 참조 형식. 에서 이전 목록 인 에 기본 형식이있는 열거 형식의 읽기 및 쓰기도 원자 적입니다. long, ulong, double 및 decimal을 비롯한 유형의 읽기 및 쓰기와 사용자 정의 유형은 원자적일 수 있습니다. 이러한 목적으로 설계된 라이브러리 함수 외에도 원자 번호의 증분 또는 감소의 경우와 같이 읽기 - 수정 - 쓰기가 보장되지는 않습니다.

결론 :

  • 독립적 인 읽기/쓰기는
  • 읽기/(예 : i++로)/쓰기를 수정 결코 원자
  • 당신 원자 (그러나 일부 데이터 유형)입니다 Interlocked 클래스 메서드를 사용하여 원 자성을 보장 할 수 있습니다.

Interlocked 기능이 충분하지 않은 경우 Monitor.Enter (컴파일러는 lock 문을 통해 노출 함)과 같이 동기화 프리미티브를 사용하는 것 외에 다른 옵션은 없습니다.

2

독자적으로 읽기 및 쓰기은 대부분의 유형 (더 긴 유형이 아닌 일반적으로 64 비트 +)에 원자 적입니다. 하지만 당신이 원하는 것은 원자 적으로 읽고 변경하고 쓰는 것입니다. 이것은 확실히 이 아니며 원자입니다.

값을 증가시킬 필요가있는 경우 IncrementDecrement 동작이있는 System.Threading.Interlocked 클래스가 있습니다.

더 복잡한 합계를 사용해야하는 경우 lock 또는 다른 구성을 사용하는 동기화가 유일한 방법입니다. 메시징 시스템에서와 같이 일을 불변으로 만들거나 공유 할 수 없도록하기 때문에 공유 데이터 액세스 문제는 발생하지 않지만 일반적으로 선행을 위해 고안되지 않으면 달성 할 수 없습니다.

0

아니요 ... 대신 System.Threading.Interlocked.Increment(ref int location)으로 가야합니다. System.Threading.Interlocked.Increment을 사용하지 않으면 프로세서가 지시를 재정렬 할 수있는 기회를 제공하는 반면 프로세서가 읽기 및 쓰기 (원 자성 인 명령어)를 정확히 원하는 순서로 실행하도록 보장하므로 잠금이 필요하지 않습니다.

많은 양의 작업을 수행 할 수 있으므로 슬레지 해머를 사용하거나 다른 작업이 필요하지 않으므로 lock을 사용할 수도 있습니다.하지만이 시나리오에서도 대신 System.Threading.ReaderWriterLockSlim을 사용하려고합니다.

btw - a nice read!