2010-07-21 4 views
8

메모리 장벽에 대한 이해를 높이려고합니다. 약한 메모리 모델이 있고 Dekker's algorithm을 적용한다고 가정합니다. 메모리 장벽을 추가하여 약한 메모리 모델에서 올바르게 작동하게 할 수 있습니까?메모리 장벽과 연동 작업

나는 대답이 놀랍다 고 생각합니다. 그 이유는 (내가 맞다면) 메모리 장벽을 사용하여 읽기가 다른 것을 지나치지 않도록 보장 할 수는 있지만, 읽기가 캐시에있는 오래된 데이터를 보지 못하게 할 수는 없다는 것입니다. 따라서 임계 구역이 (CPU의 캐시마다) 잠금 해제되었지만 현재 다른 프로세서가 잠긴 상태로 보일 수있는 시점에서 과거에 시간을 볼 수있었습니다. 필자의 이해가 정확하다면 일반적으로 테스트 - 앤 - 세트 (test-and-set) 또는 비교 - 교환 (comp-and-swap)과 같은 연동 연산을 사용하여 다중 프로세서 간의 메모리 위치에서 값의 동기화 된 일치를 보장해야합니다.

따라서 약한 메모리 모델 시스템 만 메모리 장벽을 제공 할 것이라고 기대할 수 있습니까? 시스템은 테스트 - 앤 - 세트 또는 비교 -와 - 스왑과 같은 오퍼레이션을 제공하여 유용해야합니다.

x86을 비롯한 널리 사용되는 프로세서가 약한 메모리 모델보다 훨씬 강력한 메모리 모델을 제공한다는 것을 알고 있습니다. 약한 메모리 모델에 대한 토론에 집중하십시오.

(데커의 알고리즘이 잘못 선택 인 경우 가능하면 메모리 장벽이 성공적으로 정확한 동기화를 달성 할 수있는 또 다른 상호 배제 알고리즘을 선택합니다.)

답변

5

메모리 장벽으로 인해 읽기가 최신 값을 볼 수 없다는 것은 당연합니다. 그것이하는 일은 단일 쓰레드와 쓰레드 사이에서 오퍼레이션 간의 순서를 강제하는 것입니다.

예를 들어, 스레드 A가 일련의 저장소를 수행 한 다음 플래그 위치에 최종 저장하기 전에 릴리스 장벽을 실행하고 스레드 B가 플래그 위치에서 읽고 그런 다음 다른 값을 읽기 전에 획득 장벽을 실행하면 다른 변수는 스레드 A에 의해 저장된 값이됩니다 물론

// initially x=y=z=flag=0 

// thread A 
x=1; 
y=2; 
z=3; 
release_barrier(); 
flag=1; 

// thread B 
while(flag==0) ; // loop until flag is 1 
acquire_barrier(); 
assert(x==1); // asserts will not fire 
assert(y==2); 
assert(z==3); 

을, 당신은 부하가 flag에 저장할 수 있는지 확인해야하는 것은, 간단한로드 및 저장 명령어는 가장 일반적인 CPU에서있는 (원자이다 변수가 적절하게 정렬되어있는 경우). 스레드 B의 while 루프가 없으면 스레드 B는 flag의 부실 값 (0)을 읽을 수 있으므로 다른 변수에 대해 읽은 값을 보장 할 수 없습니다.

펜스를 사용하여 Dekker의 알고리즘에서 동기화를 시행 할 수 있습니다.

여기 (C++ 0X 원자 변수를 사용하여) C의 예시적인 구현 ++ 같습니다

std::atomic<bool> flag0(false),flag1(false); 
std::atomic<int> turn(0); 

void p0() 
{ 
    flag0.store(true,std::memory_order_relaxed); 
    std::atomic_thread_fence(std::memory_order_seq_cst); 

    while (flag1.load(std::memory_order_relaxed)) 
    { 
     if (turn.load(std::memory_order_relaxed) != 0) 
     { 
      flag0.store(false,std::memory_order_relaxed); 
      while (turn.load(std::memory_order_relaxed) != 0) 
      { 
      } 
      flag0.store(true,std::memory_order_relaxed); 
      std::atomic_thread_fence(std::memory_order_seq_cst); 
     } 
    } 
    std::atomic_thread_fence(std::memory_order_acquire); 

    // critical section 


    turn.store(1,std::memory_order_relaxed); 
    std::atomic_thread_fence(std::memory_order_release); 
    flag0.store(false,std::memory_order_relaxed); 
} 

void p1() 
{ 
    flag1.store(true,std::memory_order_relaxed); 
    std::atomic_thread_fence(std::memory_order_seq_cst); 

    while (flag0.load(std::memory_order_relaxed)) 
    { 
     if (turn.load(std::memory_order_relaxed) != 1) 
     { 
      flag1.store(false,std::memory_order_relaxed); 
      while (turn.load(std::memory_order_relaxed) != 1) 
      { 
      } 
      flag1.store(true,std::memory_order_relaxed); 
      std::atomic_thread_fence(std::memory_order_seq_cst); 
     } 
    } 
    std::atomic_thread_fence(std::memory_order_acquire); 

    // critical section 


    turn.store(0,std::memory_order_relaxed); 
    std::atomic_thread_fence(std::memory_order_release); 
    flag1.store(false,std::memory_order_relaxed); 
} 

전체 분석은 다른 CPU가 닿는 경우 http://www.justsoftwaresolutions.co.uk/threading/implementing_dekkers_algorithm_with_fences.html

+1

AFAICT, Dekker 's의 경우, 깃발은 과거에 분명했지만 이제는 비판적인 섹션에 들어가는 것이 안전하다는 것을 알면 충분하지 않습니다. 내가 최신 값을 필요로하는 것처럼 들리며, 당신이 첫 번째 문장에서 말하는 것처럼 당신이 기억 장벽으로 어떻게 그것을 얻는 지 보지 못합니다. –

+0

방금 ​​전에 보았던 것보다 강한 장벽 --- "전체 울타리"가 필요합니다. 나는 Dekker 's가 장벽으로 나중에 보여주기 위해 나의 대답을 갱신 할 것이다. –

0

같은 파워 iSync와 같은 일부 장벽 (및에 .acq로드 ia64) 또한 후속 적재에 영향을 미친다. 예 :로드가 프리 페칭 때문에 isync 전에 사용 가능한 경우이를 버려야합니다. 적절하게 사용하면 약한 메모리 모델에서 Dekker의 알고리즘을 작동시키기에 충분합니다.

또한 캐시 무효화 논리가 작동합니다. 로드가 isync와 같은 것으로 인해 현재 상태이고 다른 CPU가 접속하면 캐시 된 버전의 데이터가 무효화된다는 것을 알고 있다면 충분합니까?

흥미로운 질문 외에, Dekker의 알고리즘은 모든 실용적인 목적을위한 것입니다. 실제 응용 프로그램에 원자 하드웨어 인터페이스와 메모리 장벽을 사용하려고 할 것이므로 Dekker 's를 원자로로 수정하는 방법에 중점을 두는 것이 나에게 가치있는 것 같지 않습니다.)

+0

에서 블로그 엔트리 <데이터 무효화 참조 들어 그 정도면 충분합니까?> 제 질문은 이런 종류의 보증을하지 않는 약한 모델에 관한 것입니다. 예. 내가 얻으려고하는 것은 강력한 모델에서 작동하는 알고리즘을 "충분한"메모리 장벽을 넣어 취약한 모델에서 작동하는 알고리즘으로 변환 할 수 있는지 여부입니다. –

1

로드 및 저장 장벽이 생기고, 컴파일러가 상점을 재정렬하지 않았 음을 보장합니다. 어떤 합리적인 아키텍처에서도 엄격한 일관성을 제공하지 않을까요? Dekker는 순차적으로 일관된 아키텍처에 대해 작업합니다. 순차적 일관성은 엄격한 일관성보다 약한 조건입니다.

http://www.cs.nmsu.edu/~pfeiffer/classes/573/notes/consistency.html

심지어 약한 일관성 모델을 가진 CPU에, 당신은 여전히 ​​캐시 일관성을 기대. 나는 물건이 탈선하는 곳은 저장소 버퍼와 추측 된 읽기의 동작이며 사용 가능한 작업은 저장된 쓰기를 플러시하고 추측 된 읽기를 무효화한다고 생각합니다. 추측 된 읽기를 무효화 할 수있는로드 울타리가 없거나 저장소 버퍼를 플러시하는 쓰기 울타리가없는 경우 Dekker 's를 구현할 수 없으면 뮤텍스를 구현할 수 없습니다!

여기 내 주장이 있습니다. 쓰기 장벽이 있고 읽기 장벽이 있고 캐시가 CPU 사이에 일관성이 있으면 각 명령 다음에 쓰기 (저장소 울타리)를 플러시하고 매 명령마다 추측 (읽기 펜스)을 플러시하여 모든 코드를 순차적으로 일관되게 만들 수 있습니다 교수. 그래서 나는 당신이 말하는 것에 대해 원자론을 필요로하지 않는다고 주장하며, 당신은 데커의 것만으로 필요한 것을 할 수 있다고 주장합니다. 물론 당신은 원하지 않을 것입니다.

BTW, 내가 일하는 회사 인 Corensic은 동시성 문제를 디버깅하기위한 멋진 도구를 작성합니다. http://www.corensic.com을 확인하십시오.

관련 문제