C# Rookiss Part4 게임서버 : 메모리베리어
🙇♀️메모리 베리어
A) 코드 재배치 억제 B) 가시성
🪐하드웨어 최적화
하드웨어에서 코드적으로 연관이 없다면 최적화를 위해 코드를 재배치를한다
static int x = 0;
static int y = 0;
static int r1 = 0;
static int r2 = 0;
static void Thread_1()
{
y = 1; // Store y
r1 = x; // Load X
}
static void Thread_2()
{
x = 1; // Store x
r2 = y; // Load y
}
static void Main(string[] args)
{
int count = 0;
while (true)
{
count++;
x = y = r1 = r2 = 0;
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
if (r1 == 0 && r2 == 0)
break;
}
Console.WriteLine($"{count}번 만에 빠져나옴");
}
수학적으로는 빠져나올수없지만 하드웨어 최적화로 인해 코드 재배치 발생
static void Thread_1()
{
r1 = x; // Load X
y = 1; // Store y
}
이렇게 변환되어 빠져나온다
🪐메모리 베리어로 막기
- 코드재배치 막기
- 코드 재배치를 막기위한 선을 만든다!
- Thread.MomoryBarrier사용
- MemoryBarrier
- 1) Full Memory Barrier (ASM MFENCE, C# Thread.MenoryBarrier) : Store/Load 둘 다 막는다
- 2) Store Memory Barrier (ASM SFENCE) : Store만 막는다
- 3) Load Memory Barrier (ASM LFENCE) : Load만 막는다
static void Thread_1()
{
y = 1; // Store y
// -----------------------
Thread.MemoryBarrier(); // 위아래 코드 이동 불가
r1 = x; // Load X
}
static void Thread_2()
{
x = 1; // Store x
// -----------------------
Thread.MemoryBarrier();
r2 = y; // Load y
}
🪐가시성의 역할
-
메모리 베리어는 가시성의 역할도 한다
- 가시성 식당 비유
- A 직원이 콜라 주문을 받는다
- A 직원이 주문현황에 올린다
- B 직원은 주문현황을 보고 수첩을 갱신한다
- 가시성 화장실 비유
- 화장실을 사용하고 난 뒤 물을 내린다
- 다음으로 화장실을 사용하는 사람은 물을 내리고 사용한다
A 쓰레드는 캐시에 내용을 적고 램에 동기화를 함
B 쓰레드는 동기화를 하고 캐시의 내용을 갱신함
static void Thread_1()
{
y = 1; // Store y
// -----------------------
Thread.MemoryBarrier(); // 물내리기 (정보 동기화)
r1 = x; // Load X
}
static void Thread_2()
{
x = 1; // Store x
// -----------------------
Thread.MemoryBarrier(); // 물내리기 (정보 동기화)
r2 = y; // Load y
}
- 메모리 베리어 예시
int _answer;
bool _complete;
void A()
{
_answer = 123; // store
Thread.MemoryBarrier(); // Barrier 1 정보를 저장하고 동기화
_complete = true; // store
Thread.MemoryBarrier(); // Barrier 2 정보를 저장하고 동기화
}
void B()
{
Thread.MemoryBarrier(); // Barrier 3 정보를 읽기전 동기화
if (_complete) // read
{
Thread.MemoryBarrier(); // Barrier 4 정보를 읽기전 동기화
Console.WriteLine(_answer); // read
}
}