스레드와 메모리 영역은 다중 스레드 프로그램의 성능과 안정성에 큰 영향을 미친다. 이를 이해하기 위해, 각각의 메모리 영역과 스레드의 관계를 살펴본다.
1. 스레드와 메모리 개요
- 스레드는 프로세스 내에서 실행되는 독립적인 실행 흐름이다. 하나의 프로세스에는 여러 개의 스레드가 있을 수 있으며, 각 스레드는 자신만의 실행 스택을 가지고 있지만 프로세스의 메모리 공간(코드, 힙, 데이터 등)을 공유한다.
- 프로세스는 운영 체제에 의해 실행 중인 프로그램의 인스턴스로, 메모리와 리소스를 할당받는다.
2. 메모리 영역
프로세스의 메모리 영역은 일반적으로 다음과 같이 구분된다:
- 코드 영역 (Text Segment):
- 프로그램의 실행 코드가 저장되는 영역이다.
- 읽기 전용이며, 모든 스레드가 공유한다.
- 데이터 영역 (Data Segment):
- 전역 변수와 정적 변수가 저장되는 영역이다.
- 초기화된 데이터는 초기화된 데이터 영역에, 초기화되지 않은 전역 변수는 BSS(Block Started by Symbol) 영역에 위치한다.
- 프로세스의 모든 스레드가 공유한다.
- 힙 영역 (Heap):
- 동적 메모리 할당을 위해 사용되는 메모리 영역이다.
malloc
,new
같은 동적 메모리 할당 함수에 의해 관리된다.- 모든 스레드가 접근 가능하며, 동시성 문제를 방지하기 위해 적절한 동기화가 필요하다.
- 스택 영역 (Stack):
- 각 스레드가 고유하게 가지는 메모리 영역으로, 함수 호출 시 지역 변수와 함수의 반환 주소 등을 저장한다.
- 각 스레드의 스택은 독립적이므로, 다른 스레드가 스택에 저장된 데이터를 직접 접근할 수 없다.
- 스택 메모리는 자동으로 할당 및 해제된다.
3. 스레드의 메모리 접근
- 공유 메모리:
- 코드, 데이터, 힙 영역은 프로세스 내 모든 스레드가 공유한다. 이로 인해 다중 스레드가 동일한 메모리 영역을 동시에 읽거나 쓰려 할 때 충돌(경쟁 상태)이 발생할 수 있다.
- 이러한 동시성 문제를 해결하기 위해
lock
,mutex
,semaphore
,Interlocked
클래스 등 동기화 메커니즘을 사용한다.
- 스레드 로컬 메모리:
- 스택은 각 스레드마다 독립적이다. 스레드가 함수 호출 시 생성하는 지역 변수나 함수 호출 스택 프레임은 다른 스레드와 공유되지 않는다.
- 스레드 로컬 변수는 안전하게 사용할 수 있지만, 공유 데이터가 필요할 때는 적절한 동기화가 필요하다.
4. 메모리 동기화와 문제점
- 경쟁 상태 (Race Condition):
- 두 개 이상의 스레드가 동일한 메모리 공간에 접근할 때 발생한다. 적절한 동기화 없이 변수 값을 읽고 수정하면 예기치 않은 결과가 나올 수 있다.
- 데드락 (Deadlock):
- 두 개 이상의 스레드가 서로 자원을 기다리며 무한 대기 상태에 빠지는 현상이다.
- 메모리 가시성:
- 하나의 스레드가 수정한 데이터가 다른 스레드에서 즉시 보이지 않을 수 있다. 이를 해결하기 위해
volatile
키워드나 메모리 장벽(memory barrier)을 사용한다.
- 하나의 스레드가 수정한 데이터가 다른 스레드에서 즉시 보이지 않을 수 있다. 이를 해결하기 위해
5. 동기화 메커니즘
- Mutex (Mutual Exclusion):
- 특정 코드 블록에 대한 단일 스레드 접근을 보장하기 위해 사용된다.
- Semaphore:
- 특정 개수의 스레드가 한정된 자원에 접근하도록 제어한다.
- Interlocked 클래스:
- 원자적 연산을 수행하는 데 사용되며, 다중 스레드 환경에서 값의 증가/감소 또는 교환 같은 연산을 안전하게 수행할 수 있다.
- Lock (Monitor):
- 특정 객체에 대해 잠금을 걸어 코드의 일부에 단일 스레드만 접근할 수 있도록 보장한다.
이러한 메모리 영역과 동기화 기법은 다중 스레드 프로그래밍에서 데이터의 일관성과 안전성을 보장하는 데 필수적이다.
'공부 > 게임서버' 카테고리의 다른 글
Thread.Sleep 과 Thread.Yield (0) | 2024.11.12 |
---|---|
경합 조건 (Race Condition), Interlocked (0) | 2024.11.11 |
재귀적 lock을 허용하지 않는 ReaderWriterLock 구현 예시 (0) | 2024.11.11 |
임계영역 (Critical Section) (0) | 2024.11.10 |
가시성 문제와 보장 방법 (0) | 2024.11.10 |