cppreference에서 완화 된 순서에 대한 설명이 잘못 되었습니까?


13

cppreference.com설명서std::memory_order 에는 완화 된 주문의 예가 ​​있습니다.

편안한 주문

태그 memory_order_relaxed가 지정된 원자 작업 은 동기화 작업이 아닙니다. 동시 메모리 액세스간에 순서를 부과하지 않습니다. 원 자성 및 수정 순서 일관성 만 보장합니다.

예를 들어 x와 y가 처음에 0 인 경우

// Thread 1:
r1 = y.load(std::memory_order_relaxed); // A
x.store(r1, std::memory_order_relaxed); // B
// Thread 2:
r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

스레드 1 내에서 A가 B 보다 먼저 시퀀싱 되고 스레드 2 내에서 D 보다 먼저 C가 시퀀싱 되기는하지만 , y의 수정 순서에서 D가 D보다 먼저 나타나는 것을 막을 수 는 없기 때문에 r1 == r2 == 42 생성 x의 수정 순서에서 C 앞에 나타납니다. y에 대한 D의 부작용은 나사산 1의 하중 A에서 볼 수 있지만 x에 대한 B의 부작용은 나사산 2의 하중 C에서 볼 수 있습니다. 특히, C in 전에 D가 완료된 경우 발생할 수 있습니다. 컴파일러 재정렬로 인해 또는 런타임에 스레드 2

"C는 스레드 2 내에서 D보다 먼저 시퀀싱됩니다"라고 표시됩니다.

평가 순서 에서 찾을 수있는 이전 순서의 정의에 따라 A가 B보다 먼저 순서화되면 B의 평가가 시작되기 전에 A의 평가가 완료됩니다. C는 스레드 2 내에서 D보다 먼저 시퀀싱되므로 D가 시작되기 전에 C를 완료해야하므로 스냅 샷의 마지막 문장의 조건 부분은 절대 충족되지 않습니다.


C ++ 11에 대한 질문이 있습니까?
curiousguy

아니요, c ++ 14,17에도 적용됩니다. 컴파일러와 CPU가 모두 C를 D로 재정렬 할 수 있다는 것을 알고 있지만 재정렬이 발생하면 D를 시작하기 전에 C를 완료 할 수 없습니다. 따라서 "A는 스레드 1 내에서 B보다 먼저 순서화되고 C는 스레드 2 내에서 D보다 먼저 순서화됩니다"라는 문장에 용어 오용이 있다고 생각합니다. "코드에서 A는 스레드 1 내에서 B보다 먼저 배치되고 C는 스레드 2 내에서 D보다 먼저 배치됩니다"라고 말하는 것이 더 정확합니다. 이 질문의 목표는이 생각을 확인하는 것입니다
abigaile

"재주문"이라는 용어로 정의 된 것은 없습니다.
curiousguy

답변:


12

나는 cppreference가 옳다고 믿는다. 나는 이것이 "있는 그대로"규칙 [intro.execution] / 1로 요약된다고 생각한다 . 컴파일러는 코드에서 설명하는 프로그램의 관찰 가능한 동작을 재현해야합니다. A는 서열 - 전에 관계 만이 평가가 수행되는 스레드의 관점에서 평가 사이에 확립된다 [intro.execution] / 15 . 즉,이 개 평가는 다른 어떤 스레드에서 어딘가에 표시 한 후, 코드가 실제로 작동합니다 스레드에서 실행되는 하나의 염기 서열을 때 처럼 첫 번째 평가는 실제로 두 번째 평가가하는 어떤 영향을 미쳤는가 않습니다 뭐든간에. 예를 들어

int x = 0;
x = 42;
std::cout << x;

해야한다 그러나 (42)를 인쇄, 컴파일러는 실제로 객체로 값 (42)을 저장할 필요가 없습니다 x그것을 인쇄 해당 개체에서 값 다시 읽기 전에. 또한 마지막으로 저장 될 값 x은 42 였음을 기억 하고 값 42에서 실제 저장을하기 전에 값 42를 직접 인쇄하기 만하면됩니다 x. 실제로 x지역 변수 인 경우 변수가 마지막에 할당 된 값을 추적하고 개체를 만들거나 실제로 값을 저장하지 않을 수도 있습니다. 스레드가 차이를 말할 수있는 방법이 없습니다. 동작은 항상 될 것입니다 것처럼 변수가 있었고 것처럼 값 (42)는 실제로 객체에 저장된 x 전에해당 객체에서로드됩니다. 그렇다고해서 생성 된 머신 코드가 실제로 어디에나 저장하고로드해야한다는 의미는 아닙니다. 필요한 것은 생성 된 머신 코드의 관찰 가능한 동작이이 모든 것이 실제로 발생하는 경우의 동작과 구분할 수 없다는 것입니다.

우리가 보면

r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

예, C는 D보다 먼저 시퀀싱됩니다. 그러나이 스레드에서 단독으로 볼 때 C는 D의 결과에 영향을 미치지 않습니다. D는 C의 결과를 변경하지 않습니다. 다른 스레드에서 발생하는 간접적 인 결과로. 그러나을 지정 std::memory_order_relaxed하면 명시 적으로다른 스레드가로드 및 저장을 관찰하는 순서는 관련이 없습니다. 다른 스레드는로드를 관찰하고 특정 순서로 저장할 수 없으므로 C와 D가 일관된 방식으로 서로 영향을 미치도록 할 수있는 다른 스레드는 없습니다. 따라서로드 및 저장이 실제로 수행되는 순서는 관련이 없습니다. 따라서 컴파일러는 자유롭게 순서를 바꿀 수 있습니다. 그리고 그 예 아래의 설명에서 언급했듯이 D의 저장이 C의로드 전에 수행되면 r1 == r2 == 42가 실제로 올 수 있습니다 ...


따라서 기본적으로 C는 D 전에 발생해야 한다고 표준에 명시되어 있지만 컴파일러는 C 또는 D가 다음에 발생했는지 여부를 증명할 수 없으며 as-if 규칙으로 인해 어쨌든 순서를 바꿉니다.
Fureeish

4
@Fureeish No. C는 D가 발생하는 스레드가 말할 수있는 한 D보다 먼저 발생해야합니다. 다른 맥락에서 관찰하는 것은 그 견해와 일치하지 않을 수 있습니다.
중복 제거기

"처럼 규칙"이 없습니다
curiousguy

4
@curiousguy이 주장은 이전의 다른 C ++ 전도 와 비슷해 보입니다 .
궤도에서 가벼움 경주

1
@curiousguy이 표준은 않습니다 각주에서 그것의 조항 "는 등의-경우 규칙"의 라벨 하나를 : AS-경우 "규칙" "이 조항은 때때로라고" intro.execution
Caleth

1

서로에 대해 해당 시퀀스에서 동작의 상대적 순서를 암시하지 않고, 액션이 두 개의 다른 동작 시퀀스에 대해 순서화되는 것이 때때로 가능하다.

예를 들어, 하나에 다음 세 가지 이벤트가 있다고 가정하십시오.

  • 1을 p1에 저장
  • 온도에 p2를로드
  • 2에서 p3까지 저장

p2의 판독은 p1의 기록 후 및 p3의 기록 전에 독립적으로 정렬되지만, p1 및 p3 모두가 참여하는 특정 순서는 없다. p2로 수행 된 작업에 따라 컴파일러가 p3을 지나서 p1을 연기하고 p2로 필요한 의미를 달성하는 것은 실용적이지 않을 수 있습니다. 그러나 컴파일러가 위의 코드가 더 큰 시퀀스의 일부라는 것을 알고 있다고 가정합니다.

  • 1에서 p2까지 저장 [p2의로드 전에 순서 지정]
  • [위를 수행]
  • p1에 3을 저장하십시오 [p1에 다른 저장 후 순서]

이 경우 위 코드 이후에 상점을 p1으로 재정렬하고 다음 상점과 통합하여 p1을 먼저 쓰지 않고 p3를 작성하는 코드를 생성 할 수 있다고 판별 할 수 있습니다.

  • 온도를 1로 설정
  • 온도를 p2에 저장
  • 2에서 p3까지 저장
  • 3을 p1에 저장

비록 데이터 의존성으로 인해 시퀀싱 관계의 특정 부분이 전 이적으로 동작하는 것처럼 보일 수 있지만, 컴파일러는 명백한 데이터 의존성이 존재하지 않는 상황을 식별 할 수 있으며, 따라서 예상되는 전이 효과가 없을 수 있습니다.


1

두 개의 명령문이있는 경우 컴파일러는 코드를 순차적으로 생성하므로 첫 번째 코드는 두 번째 코드보다 먼저 배치됩니다. 그러나 cpus에는 내부에 파이프 라인이 있으며 어셈블리 작업을 병렬로 실행할 수 있습니다. 명령문 C는로드 명령입니다. 메모리를 가져 오는 동안 파이프 라인은 다음 몇 가지 명령어를 처리하고로드 명령어에 종속되지 않는 경우 C가 완료되기 전에 실행될 수 있습니다 (예 : D에 대한 데이터는 캐시에 있고 C는 메인 메모리에 있음).

사용자가 실제로 두 명령문을 순차적으로 실행해야하는 경우보다 엄격한 메모리 순서 지정 조작을 사용할 수 있습니다. 일반적으로 사용자는 프로그램이 논리적으로 올바른 한 신경 쓰지 않습니다.


-7

당신이 생각하는 것은 똑같이 유효합니다. 표준은 순차적으로 실행되는 것, 그렇지 않은 것 및 혼합 방법을 말하지 않습니다 .

다중 PhD에 해당하는 작업의 혼란에 대한 일관된 의미론을 구성하는 것은 귀하와 모든 단일 프로그래머에게 달려 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.