ProgramingTip

읽기 메모리 장벽과 인증서를 이해하는 방법

bestdevel 2020. 12. 29. 07:42
반응형

읽기 메모리 장벽과 인증서를 이해하는 방법


언어 일부 volatile는 변수를 지원하는 메모리를 읽기 전에 "읽기 메모리 장벽"수행하는 것으로을 설명 되는 수정자를 제공 합니다.

읽기 메모리 배리어는 일반적으로 배리어 이후 요청 된 읽기를 수행하기 전에 CPU가 배리어 전에 요청한 읽기를 수행 확인하는 방법으로 설명됩니다. 그러나이 정의를 사용하면 오래된 값을 읽을 수있는 것처럼 보입니다. 즉, 즉, 순서로 읽기를 수행 할 때 이후 읽은 값이 실제로 참조 할 시점에 시스템의 최신 값을 참조 확인하기 위해 주 메모리 나 CPU를 참조합니다. 읽기 장벽.

인증서 인증서는 실제로 최신 값을 읽었는지 또는 읽은 값이 읽었는지 이전의 값만큼 최신인지 보장? 아니면 다른 해석? 이 답변의 어떤 의미는 무엇입니까?


장벽과 장벽이 있습니다. 장벽을 지키고 장벽을 해제하십시오. 기타 (io 대 메모리 등).

값의 "최신"값 또는 "신선도"를 제어하는 ​​장벽은 없습니다. 메모리 액세스의 최다 순서를 제어하기 위해 존재합니다.

쓰기 장벽은 쓰기 순서를 제어합니다. 메모리에 대한 쓰기가 느리기 때문에 (CPU의 속도에 비해) 일반적으로 쓰기가 '실제로 발생하기'전에 게시되는 쓰기 요청이 있습니다. 순서대로 순서에 순서에 순서대로 순서를 순서대로 표시합니다. (또는 'queue'가 최고의 이름이 아닐 수도 있습니다 ...) 재정렬을 방지하기 위해 쓰기 장벽을 사용하지 않는 한.

제어 할 수 있습니다. 추론 적 실행 (CPU가 미리보고 메모리에서 일찍로드 됨) 및 쓰기 버퍼가 존재하기 때문에 (CPU는 값이있는 경우에 쓰기 버퍼에서 읽습니다. 즉 CPU는 X를 방금 쓴 것으로 생각합니다.) = 5 , 쓰기 왜 다시 읽어야하는지 , 쓰기 버퍼에서 5 가되기 위해 여전히 대기 중인지 확인하십시오. ) 순서가 잘못 될 수 있습니다.

이 컴파일러가 생성 된 코드의 순서와 관련하여 무엇을 수행하는지에 대한 사실입니다. 즉, C ++의 '인증서'는 여기에서 도움이되지 않습니다. 컴파일러에게 "메모리"에서 값을 다시 읽도록 코드를 출력 지시하기 만하 기 때문에 CPU에 어떻게 / 어디에서 읽을 것인지 알려주지 (예 : "메모리"CPU 수준에서 많은 것입니다).

따라서 읽기 / 쓰기 장벽은 읽기 / 쓰기 방면에서 재정렬을 방지하기 위해 블록을 배치합니다 (읽기는 일반적으로 널이 많지는 않지만 재정렬 효과는 동일합니다).

어떤 종류의 블록? -블록 금액 및 / 또는 해제.

Acquire- 예를 들어 read-acquire (x)는 읽기 큐에 x의 읽기를 추가하고 큐를 플러시합니다 (실제로 큐를 플러시하지 않지만 읽기 전에 아무것도 다시하지 않는다는 마커를 추가합니다. . 나중에 나중에 (코드 순서대로) 읽기를 다시 시작 할 수 있습니다.

릴리스-예를 들어 write-release (x, 5)는 먼저 큐를 플러시 (또는 마커) 한 다음 쓰기 요청을 쓰기 큐에 추가합니다. 따라서 이전 쓰기는 x = 5 이후에 발생하는 재정렬하지 않지만 나중에 쓰기는 x = 5 이전에 재정렬 될 수 있습니다.

이것은 일반적이지만 다른 조합이 가능하기 때문에 읽기와 쓰기 및 쓰기를 릴리스와 쌍을 이룹니다.

비용 및 해제는 재주문이 한 방향으로 만 진행되는 것을 막기 때문에 '반 장벽'또는 '반 울타리'로 처리됩니다.

전체 장벽 (또는 전체 울타리)은 금액 및 해제 모두에 적용됩니다. 즉, 재정렬이 없습니다.

일반적으로 잠금없는 프로그래밍 또는 C # 또는 Java 인증서의 경우 원하는 / 필요한 이해 읽기 및 쓰기 해제입니다.

void threadA()
{
   foo->x = 10;
   foo->y = 11;
   foo->z = 12;
   write_release(foo->ready, true);
   bar = 13;
}
void threadB()
{
   w = some_global;
   ready = read_acquire(foo->ready);
   if (ready)
   {
      q = w * foo->x * foo->y * foo->z;
   }
   else
       calculate_pi();
}

따라서 이는 프로그래밍하는 잘못된 방법입니다. 자물쇠가 더 안전 할 것입니다. 하지만 장벽을 설명하기 위해 ...

threadA ()가 foo 작성을 완료 한 후에는 foo-> 준비 완료, 마지막으로 작성해야합니다. 두 가지 다른 언어가 foo-> 준비된 사전보고 잘못된 x / y / z 값을 얻을 수 있습니다. 따라서 write_release위에서 언급했듯이 쓰기 큐를 사용하는 '플러시'(x, y, z가 커밋) 한 다음 준비 = true 요청을 에 추가 하는 foo-> 준비를합니다. 그런 다음 바 = 13 요청을 추가합니다. 릴리스 장벽 (전체가 아님)을 방금 사용했기 때문에 bar = 13이 준비되기 전에 기록 될 수 있습니다. 그러나 우리는 상관하지 않습니다! 즉, 바가 공유 데이터를 변경하지 않는다고 가정합니다.

이제 threadB ()는 우리가 '준비'라고 말할 때 실제로 준비가 실시하는 것을 알 필요가 있습니다. 그래서 우리는 read_acquire(foo->ready). 이 읽기는 읽기 큐에 추가되고 큐는 플러시됩니다. 참고 w = some_global도 여전히 큐에있을 수 있습니다. 따라서 foo-> ready는 전에 읽을 수 있습니다 some_global. 그러나 다시 말하지만, 우리가 그렇게 조심하고 중요한 데이터의 일부가 아니기 때문에 우리는 신경 쓰지. 우리가 신경 쓰는 것은 foo-> x / y / z입니다. 따라서 플러시 / 마커 후 읽기 읽기에 추가되어 foo-> ready를 읽은 후에 만 ​​읽을 수 있습니다.

또한 이것은 일반적으로 mutex / CriticalSection 등의 잠금 및 잠금 해제에 사용되는 것과 동일한 동일한 장벽이라는 점에 유의하십시오. (즉, 잠금 ()에서 금액, 잠금 해제 ()에서 해제).

그래서,

  • 나는 인증서가 (즉 취득 / 출시됨) MS 문서가 C #에서 '확실히'라고 말하는 것과 정확히 일치합니다 (선택적으로 MS C ++의 경우이지만 이것은 비표준입니다). http://msdn.microsoft.com/en-us/library/aa645755(VS.71).aspx참조하십시오 . "먼저 발급 인증서"의미 금액 "이 있습니다. 즉, 메모리에 대한 참조보다 발생하도록 보장됩니다. 그 후에 발생하는 ..."

  • 나는 익숙하지 않지만 자바는 같다고 생각한다 . 일반적으로 읽기-획득 / 쓰기-릴리스보다 더 많은 보증이 필요하지 않으므로 정확히 동일하다고 생각합니다.

  • 당신의 질문에서 당신은 그것이 정말로 상대적인 순서에 관한 것이라고 생각할 때 올바른 길을 가고 있었다.-당신은 단지 역순으로 순서를 가졌다. (즉, "읽은 값은 적어도 장벽 이전의 읽기만큼 최신인가?" "-아니요, 장벽 이전의 읽기는 중요하지 않습니다. 이후에 보장되는 장벽 이후의 읽기, 쓰기의 경우 그 반대).

  • 그리고 언급했듯이 재정렬은 읽기와 쓰기 모두에서 발생하므로 한 스레드에만 장벽을 사용하고 다른 스레드에는 장벽을 사용하지 않습니다. 즉, 읽기-획득없이 쓰기-릴리스로는 충분하지 않습니다. 즉, 올바른 순서로 작성하더라도 쓰기 장벽과 함께 가기 위해 읽기 장벽을 사용하지 않으면 잘못된 순서로 읽을 수 있습니다.

  • 마지막으로, 잠금없는 프로그래밍과 CPU 메모리 아키텍처는 실제로 그보다 훨씬 더 복잡 할 수 있지만 획득 / 해제를 고수하면 꽤 멀리 갈 수 있습니다.


volatile대부분의 프로그래밍 언어에서 실제 CPU 읽기 메모리 장벽을 의미하지는 않지만 레지스터의 캐싱을 통해 읽기를 최적화하지 않도록 컴파일러에 명령합니다. 이것은 읽기 프로세스 / 스레드가 "결국"값을 얻게됨을 의미합니다. 일반적인 기술은 volatile시그널 핸들러에서 설정되고 메인 프로그램 루프에서 검사 할 부울 플래그 를 선언하는 것 입니다.

반대로 CPU 메모리 장벽은 CPU 명령어를 통해 직접 제공되거나 특정 어셈블러 니모닉 (예 : lockx86의 접두사)과 함축되어 있으며, 예를 들어 메모리 매핑 된 IO 레지스터에 대한 읽기 및 쓰기 순서가 중요한 하드웨어 장치와 통신 할 때 사용됩니다. 다중 처리 환경에서 메모리 액세스 동기화.

귀하의 질문에 답하기 위해-아니요, 메모리 장벽은 "최신"값을 보장하지 않습니다.메모리 액세스 작업의 순서 . 이것은 예를 들어 잠금없는 프로그래밍 에서 중요합니다 .

다음 은 CPU 메모리 장벽에 대한 입문서 중 하나입니다.

참조 URL : https://stackoverflow.com/questions/1787450/how-do-i-understand-read-memory-barriers-and-volatile

반응형