2017-05-24 8 views
1

Joe Albahari가 C#의 volatile을 설명하는 아주 좋은 기사가 있습니다 : Threading in C#: PART 4: ADVANCED THREADING.휘발성 읽기/쓰기 및 명령 순서 재 지정

public class IfYouThinkYouUnderstandVolatile 
{ 
    private volatile int x, y; 

    private void Test1() // Executed on one thread 
    { 
    this.x = 1; // Volatile write (release-fence) 
    int a = this.y; // Volatile read (acquire-fence) 
    } 

    private void Test2() // Executed on another thread 
    { 
    this.y = 1; // Volatile write (release-fence) 
    int b = this.x; // Volatile read (acquire-fence) 
    } 
} 

기본적으로 그가 말하는 것은 ab 두 방법은 병렬로 다른 스레드에서 실행중인 경우 0를 포함 끝낼 수 있다는 것입니다 :

고려 명령 재정렬 조이 예제를 사용합니다.

IOW 최적화 또는 다음과 같이 명령을 다시 정렬 할 수 프로세서 : 우리가 volatile를 사용하고 있지만 이런 일이 왜

public class IfYouThinkYouUnderstandVolatileReordered 
{ 
    private volatile int x, y; 

    private void Test1() // Executed on one thread 
    { 
    int tempY = this.y; // Volatile read (reordered) 
    this.x = 1; // Volatile write 
    int a = tempY; // Use the already read value 
    } 

    private void Test2() // Executed on another thread 
    { 
    int tempX = this.x; // Volatile read (reordered) 
    this.y = 1; // Volatile write (release-fence) 
    int b = tempX; // Use the already read value 
    } 
} 

이유는 가 이동할 수있는 쓰기 명령 다음 명령을 읽을 수 있다는 것입니다 쓰기 지침 전에.

지금까지 나는 여기서 무슨 일이 일어나고 있는지 이해하고 있습니다.

내 질문 : 스택 프레임을 통해 재주문이 가능합니까? 다른 방법 (또는 속성 접근 자)에서 일어나는 휘발성 읽기 명령어 다음에 휘발성 쓰기 명령어를 옮길 수 있습니까?

다음 코드를 살펴보십시오. 인스턴스 변수에 직접 액세스하는 대신 속성을 사용하고 있습니다.

이 경우 재정렬은 어떻게됩니까? 어쨌든 일어날 수 있을까요? 또는 속성 액세스가 컴파일러에 의해 인라인 될 경우에만 발생할 수 있습니까?

public class IfYouThinkYouUnderstandVolatileWithProps 
{ 
    private volatile int x, y; 

    public int PropX 
    { 
    get { return this.x; } 
    set { this.x = value; } 
    } 

    public int PropY 
    { 
    get { return this.y; } 
    set { this.y = value; } 
    } 

    private void Test1() // Executed on one thread 
    { 
    this.PropX = 1; // Volatile write (release-fence) 
    int a = this.PropY; // Volatile read (acquire-fence) 
    } 

    private void Test2() // Executed on another thread 
    { 
    this.PropY = 1; // Volatile write (release-fence) 
    int b = this.PropX; // Volatile read (acquire-fence) 
    } 
} 
+0

휘발성은 모두 멈추지 않습니다 ** 모든 ** 재주문이 키워드를 사용하면 같은 유형의 작업을 다시 정렬 할 수 있습니다 (쓰기 전에 두 가지 읽기와 두 번 읽는 것). – VMAtm

답변

1

제어 할 수 없기 때문에 이러한 고수준 사항에 대해서는 생각하지 않아야합니다. JIT에는 인라인해야 할 이유가 많이 있습니다. 순서 바꾸기는 병렬 코드 실행의 가능한 결과를 추론 할 수있는 좋은 개념입니다. 하지만 실제로 일어나는 일은 읽기/쓰기 작업을 재정렬하는 것 뿐만이 아닙니다. JIT에 의한 CPU 레지스터의 값의 재주문 또는 캐싱, 또는 CPU 자체의 추측 실행 효과 또는 메모리 컨트롤러가 그 작업을 수행하는 방법 일 수 있습니다.

포인터 크기 (또는 그 이하)의 메모리 조각 읽기 및 쓰기를 생각해보십시오. 이러한 읽기 및 쓰기 작업을 수행하는 모델을 사용하고 프로그램이 실행되는 JIT 또는 CPU의 특성에 의존하지 마십시오.

1

으로는 CLI의
규약 준수가 실행의 단일 스레드 내에서 보장 어떤 기술을 사용하여 프로그램 실행할 무료 있습니다 I.12.6.4 최적화

ECMA-335

했다 스레드에 의해 생성 된 부작용과 예외는 CIL에 의해 지정된 순서대로 표시됩니다.
이 목적으로 휘발성 읽기 (휘발성 읽기 포함)만이 눈에 보이는 부작용을 구성합니다. 휘발성 작업 만 가시적 인 부작용을 구성하지만 휘발성 작업은 비 휘발성 참조의 가시성에도 영향을줍니다. 휘발성 작업은 §12.6.7에서 지정됩니다.(예 : 예외가 때때로 "비동기 예외" (예를 들어, System.Threading.ThreadAbortException)라고하는 다른 스레드에 의해 스레드에 주입 예외를 기준으로 어떤 순서 보장이 없습니다. 그래서

, 분명히 모든 인라인 할 수 있어요 그 코드와 동일합니다.