Automic
2025. 3. 20. 21:42ㆍHigh Level Programming Language
다음과 같은 코드가 있습니다.
int a = 1;
int b = 2;
a = b;
위 코드를 Intel CPU의 x86 어셈블리어로 변환하면, a = b;
코드는 메모리에서 값을 로드하고 저장하는 명령어로 변환됩니다.
일반적인 32비트 x86 어셈블리어 코드로 표현하면 다음과 같습니다.
mov eax, DWORD PTR [b] ; 변수 b의 값을 레지스터 eax에 로드
mov DWORD PTR [a], eax ; eax의 값을 변수 a에 저장
64비트 환경에서는 64비트 레지스터를 사용할 수도 있습니다.
mov rax, QWORD PTR [b] ; 변수 b의 값을 rax 레지스터에 로드
mov QWORD PTR [a], rax ; rax의 값을 변수 a에 저장
여기서 DWORD PTR
과 QWORD PTR
은 32비트 또는 64비트 변수를 다룬다는 의미입니다.
만약 컴파일러가 최적화를 수행하면, mov eax, [b]
와 같은 더 간단한 형태로 변환될 수도 있습니다.
그런데, a = b;
는 일반적으로 원자적(atomic) 연산이 아닙니다. 즉, 이 코드가 실행되는 동안 다른 스레드가 개입할 가능성이 있으며, 원자성이 보장되지 않습니다.
이유
- 메모리 접근 과정
a = b;
는 두 단계의 명령어로 실행됩니다.b
의 값을 읽어 레지스터에 로드 (mov eax, [b]
)eax
의 값을a
에 저장 (mov [a], eax
)
- CPU가 이 두 단계 사이에 다른 작업을 수행할 수도 있습니다.
- 멀티스레드 환경에서의 문제
- 다른 스레드가
b
를 변경하거나,a
를 읽는 경우 예기치 않은 동작이 발생할 수 있습니다. - 예를 들어, 첫 번째 단계(
mov eax, [b]
)와 두 번째 단계(mov [a], eax
) 사이에 다른 스레드가b
를 변경하면,a
에는 예상과 다른 값이 저장될 수 있습니다.
- 다른 스레드가
원자성을 보장하는 방법
volatile
사용 (하지만 완벽한 해결책은 아님)- Java의
volatile
키워드는 가시성(visibility)은 보장하지만 원자성(atomicity)은 보장하지 않습니다.
- Java의
synchronized
사용 (Java에서)synchronized
블록을 사용하면 해당 코드 블록이 단일 스레드에서만 실행되도록 보장할 수 있습니다.
std::atomic
사용 (C++에서)- C++에서는
std::atomic<int>
를 사용하면 원자적 연산이 가능합니다.
- C++에서는
- CPU의 원자적 명령어 사용 (
LOCK
prefix,xchg
)- x86 CPU에서는
LOCK
접두사를 사용한mov
또는xchg
명령어를 활용하여 원자성을 보장할 수 있습니다. - 예제:
mov eax, [b] ; b 값을 읽음 lock xchg [a], eax ; a와 eax를 원자적으로 교환
- x86 CPU에서는
- 메모리 배리어 사용 (Memory Barrier, Fence)
- 특정 플랫폼에서는 메모리 배리어(MFENCE, SFENCE, LFENCE)를 사용하여 CPU의 재정렬을 방지할 수도 있습니다.
결론
특정 코드 수정 없이 a = b;
를 실행하면 원자성이 항상 보장되지 않습니다. 원자성이 필요한 경우, synchronized
, std::atomic
, 혹은 CPU의 원자적 명령어를 사용해야 합니다.
'High Level Programming Language' 카테고리의 다른 글
Namespace (1) | 2025.02.23 |
---|---|
java package-qualified class name (0) | 2025.01.16 |
Java Advanced Programming Quiz 문제 (0) | 2024.07.23 |
Java Tutorials (0) | 2024.06.25 |
고급 프로그래밍 언어(High Level Programming Language) (0) | 2024.06.23 |