OpenMP에서 원자와 중요의 차이점은 무엇입니까?


111

OpenMP에서 원자와 중요의 차이점은 무엇입니까?

할 수있어

#pragma omp atomic
g_qCount++;

그러나 이것은 다음과 같지 않습니다.

#pragma omp critical
g_qCount++;

?

답변:


173

g_qCount에 대한 효과는 동일하지만 수행되는 작업이 다릅니다.

OpenMP 중요 섹션은 완전히 일반적이며 임의의 코드 블록을 둘러 쌀 수 있습니다. 그러나 스레드가 중요 섹션에 들어오고 나갈 때마다 상당한 오버 헤드가 발생하여 이러한 일반성에 대한 비용을 지불합니다 (직렬화의 고유 비용 외에도).

(또한 OpenMP에서는 이름이 지정되지 않은 모든 중요 섹션이 동일한 것으로 간주됩니다 (원하는 경우 이름이 지정되지 않은 모든 중요 섹션에 대해 하나의 잠금 만 있음). [unnamed] critical section. 짐작할 수 있듯이 명명 된 중요 섹션을 사용하여이 문제를 해결할 수 있습니다.

원자 적 연산은 오버 헤드가 훨씬 낮습니다. 가능한 경우 원자 적 증분 작업을 제공하는 하드웨어를 활용합니다. 이 경우 코드 줄을 입력 / 종료 할 때 잠금 / 잠금 해제가 필요하지 않으며 하드웨어가 간섭 할 수 없다고 알려주는 원자 적 증분 만 수행합니다.

장점은 오버 헤드가 훨씬 낮고 원자 작업에있는 하나의 스레드가 발생하려고하는 (다른) 원자 작업을 차단하지 않는다는 것입니다. 단점은 atomic이 지원하는 제한된 작업 집합입니다.

물론 두 경우 모두 직렬화 비용이 발생합니다.


5
"휴대 성을 잃을 수 있습니다"-이것이 사실인지 잘 모르겠습니다. 표준 (버전 2.0) 원자 작업이 허용되는 지정 (기본적으로 같은 것들 ++*=) 그들은 하드웨어에서 지원하지 않는 경우, 그들은로 대체 될 수 있다는 critical부분.
Dan R

@DanRoche : 네, 당신 말이 맞습니다. 나는 그 진술이 정확하지 않다고 생각합니다. 지금 바로 정정하겠습니다.
Jonathan Dursi

며칠 전 OpenMP 튜토리얼을 따랐고 내가 이해하는 한 두 가지 다른 코드에 차이가 있습니다. 즉, 임계 섹션이 명령이 스레드에 의해 한 번에 실행되도록 보장하기 때문에 결과가 다를 수 있지만 명령은 다음과 같을 수 있습니다. g_qCount = g_qCount + 1; 스레드 1의 경우 단순히 g_qCount 결과를 RAM 메모리가 아닌 쓰기 버퍼에만 저장하고 스레드 2가 g_qCount 값을 가져올 때 쓰기 버퍼가 아닌 RAM에있는 결과를 읽습니다. 원자 명령 보증한다는 명령은 메모리에 데이터를 플러시
Giox79

31

OpenMP에서 이름이 지정되지 않은 모든 중요 섹션은 상호 배타적입니다.

critical과 atomic의 가장 중요한 차이점은 atomic은 단일 할당 만 보호 할 수 있으며 특정 연산자와 함께 사용할 수 있다는 것입니다.


13
이것은 이전 답변에 대한 주석 (또는 편집)이 더 낫습니다.
kynan

20

중요 섹션 :

  • 코드 블록의 직렬화를 보장합니다.
  • "name"태그를 적절히 사용하여 블록 그룹을 직렬화하도록 확장 할 수 있습니다.

  • 천천히!

원자 작동 :

  • 훨씬 빠릅니다!

  • 특정 작업의 직렬화 만 보장합니다.


9
그러나이 대답은 매우 읽을 수있는 첫 번째 대답의 큰 합계 최대 것
마이클 Miszczyszyn

7

가장 빠른 방법은 중요하지도 원자 적이지도 않습니다. 대략적으로 임계 부 추가는 단순 추가보다 200 배 더 비싸고 원자 추가는 단순 추가보다 25 배 더 비쌉니다.

가장 빠른 옵션 (항상 적용되는 것은 아님)은 각 스레드에 자체 카운터를 제공하고 총 합계가 필요할 때 작업을 줄이는 것입니다.


2
나는 당신이 설명에 언급 한 모든 숫자에 동의하지 않습니다. x86_64를 가정하면 원자 적 작업에는 대략 한주기의 비용에 대해 몇 가지주기 오버 헤드 (캐시 라인 동기화)가 있습니다. 그렇지 않으면``진정한 공유 ''비용이 발생한다면 오버 헤드는 허무합니다. 중요한 섹션은 잠금 비용이 발생합니다. 잠금이 이미 사용되었는지 여부에 따라 오버 헤드는 대략 2 개의 원자 적 명령어 또는 두 번의 스케줄러 실행과 휴면 시간입니다. 이는 일반적으로 200 배 이상입니다.
Klaas van Gend

6

의 한계 atomic가 중요합니다. OpenMP 사양 에 대해 자세히 설명해야합니다 . MSDN 은 변경되지 않을 경우 놀라지 않을 것이므로 빠른 치트 시트를 제공합니다. (Visual Studio 2012에는 2002 년 3 월부터 OpenMP가 구현되었습니다.) MSDN 인용 :

식 문은 다음 형식 중 하나 여야합니다.

xbinop =expr

x++

++x

x--

--x

앞의 표현식에서 : 스칼라 유형 x이있는 lvalue표현식입니다. expr은 스칼라 유형이있는 표현식이며로 지정된 객체를 참조하지 않습니다 x. binop가 오버로드 연산자 아니며 중 하나 인 +, *, -, /, &, ^, |, <<, 또는 >>.

가능한 atomic경우 사용 하고 그렇지 않은 경우 중요 섹션을 명명 하는 것이 좋습니다 . 이름을 지정하는 것이 중요합니다. 이런 식으로 디버깅 문제를 피할 수 있습니다.


1
이것이 전부는 아닙니다. 다음과 같은 다른 고급 원자 지시문이 있습니다. #pragma omp aromic update (또는 read, upate, write, capture) 그래서 다른 유익한 진술을 할 수 있습니다
pooria

1

여기에 이미 훌륭한 설명이 있습니다. 그러나 우리는 조금 더 깊이 잠수 할 수 있습니다. OpenMP에서 원자중요 섹션 개념 의 핵심 차이점을 이해하려면 먼저 잠금 개념을 이해해야합니다 . lock 을 사용해야하는 이유를 살펴 보겠습니다 .

병렬 프로그램이 여러 스레드에 의해 실행되고 있습니다. 결정 론적 결과는 이러한 스레드간에 동기화 를 수행하는 경우에만 발생 합니다. 물론 스레드 간의 동기화 가 항상 필요한 것은 아닙니다. 동기화 가 필요한 경우를 언급하고 있습니다.

다중 스레드 프로그램에서 스레드 를 동기화 하기 위해 lock을 사용 합니다. 한 번에 하나의 스레드로만 액세스를 제한해야하는 경우 잠금 이 작동합니다. 로크 의 개념의 구현은 프로세서와 프로세서에 따라 달라질 수있다. 알고리즘 관점에서 간단한 잠금이 어떻게 작동하는지 알아 봅시다.

1. Define a variable called lock.
2. For each thread:
   2.1. Read the lock.
   2.2. If lock == 0, lock = 1 and goto 3    // Try to grab the lock
       Else goto 2.1    // Wait until the lock is released
3. Do something...
4. lock = 0    // Release the lock

주어진 알고리즘은 다음과 같이 하드웨어 언어로 구현 될 수 있습니다. 우리는 단일 프로세서를 가정하고 그 안에서 잠금 동작을 분석 할 것입니다. 이 연습을 위해 MIPS , Alpha , ARM 또는 Power 프로세서 중 하나를 가정 해 보겠습니다 .

try:    LW R1, lock
        BNEZ R1, try
        ADDI R1, R1, #1
        SW R1, lock

이 프로그램은 괜찮은 것 같지만 그렇지 않습니다. 위의 코드는 이전 문제를 겪고 있습니다. 동기화 . 문제를 찾아 봅시다. 잠금의 초기 값을 0이라고 가정합니다. 두 스레드가이 코드를 실행하면 하나는 SW R1에 도달하고 다른 스레드 가 잠금 변수를 읽기 전에 잠글 수 있습니다. 따라서 둘 다 자물쇠 가 무료 라고 생각합니다 . 이 문제를 해결하기 위해 간단한 LWSW 대신 다른 명령이 제공됩니다 . 이를 Read-Modify-Write 명령어 라고 합니다. 한 번에 잠금 획득 절차가 단 하나의 명령 으로 만 수행되도록 스레드 를 보장하는 복잡한 명령어 (하위 명령어로 구성됨)입니다 . 읽기-수정-쓰기 의 차이점간단한 읽기쓰기 지침 과 비교하여 로드저장 의 다른 방법을 사용한다는 것 입니다. 그것은 사용 LL 잠금 변수와로드 (링크로드) SC 잠금 변수에 쓰기 (저장 조건을). 추가 링크 레지스터 는 잠금 획득 절차가 단일 스레드에 의해 수행되도록 보장하는 데 사용됩니다. 알고리즘은 다음과 같습니다.

1. Define a variable called lock.
2. For each thread:
   2.1. Read the lock and put the address of lock variable inside the Link Register.
   2.2. If (lock == 0) and (&lock == Link Register), lock = 1 and reset the Link Register then goto 3    // Try to grab the lock
       Else goto 2.1    // Wait until the lock is released
3. Do something...
4. lock = 0    // Release the lock

링크 레지스터가 재설정 될 때 다른 스레드가 잠금이 해제 된 것으로 가정하면 증가 된 값을 잠금에 다시 쓸 수 없습니다. 따라서 잠금 에 대한 액세스의 동시성은 변수 이 획득됩니다.

크리티컬원자 성의 핵심 차이점은 다음 과 같은 아이디어에서 비롯됩니다.

잠금 변수로 실제 변수 (작업을 수행하는)를 사용할 수 있지만 잠금 (새 변수)을 사용하는 이유는 무엇입니까?

사용하여 A 새로운 가변를 잠금하기 에 이어질 임계 부분 은 USING하면서, 실제 발생할 것 같은 로크 변수 원자 개념. 임계 섹션은 실제 변수에 대해 많은 계산 (한 줄 이상)을 수행 할 때 유용합니다. 그 계산 결과가 실제 변수에 기록되지 않으면 전체 절차를 반복하여 결과를 계산해야하기 때문입니다. 이것은 고도로 계산 된 영역에 들어가기 전에 잠금이 해제 될 때까지 기다리는 것과 비교하여 성능이 저하 될 수 있습니다. 따라서 단일 계산 (x ++, x--, ++ x, --x 등)을 수행하고 사용할 때마다 atomic 지시문 을 사용하는 것이 좋습니다 .더 복잡한 영역이 집중 섹션에서 수행 될 때 중요한 지시.


-5

atomic은 단일 명령어에 대해서만 상호 배제를 활성화해야 할 때 상대적으로 성능 효율적입니다.


13
이것은 설명없이 받아 들여진 대답을 어설픈 표현에 불과합니다.
High Performance Mark

-5

atomic은 단일 명령문 Critical 섹션입니다. 즉, 하나의 명령문 실행에 대해 잠급니다.

중요 섹션은 코드 블록에 대한 잠금입니다.

좋은 컴파일러는 두 번째 코드를 첫 번째 코드와 같은 방식으로 번역합니다.


그건 틀렸어요. 당신이 이해하지 못하는 것에 대해 말하지 마십시오.
jcsahnwaldt Monica 복원
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.