using System;
namespace ServerCore
{
class Program
{
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()
{
y = 1; // Store y
// ----------------------------
Thread.MemoryBarrier();
r1 = x; // Load x
}
static void Thread_2()
{
x = 1; // Store x
// ----------------------------
Thread.MemoryBarrier();
r2 = y; // Load y
}
무조건 명령을 내린 순서대로 강제할 수 있다.
종류
1) Full Memory Barrier(ASM MFENCE, C# Thread.MemoryBarrier) : Store/Load 둘다 막는다.
2) Store Memory Barrier(ASM SFENCE) : Store만 막는다.
3) Load Memory Barrier(ASM LFENCE) : Load만 막는다.
메모리 베리어 용도
1) 코드 재배치 억제
경계선을 만들어 순서가 바뀌지 안도록 한다.
2) 가시성
프로그램입장에서의 가시성을 말한다.
베리어 코드를 만나면 실제 메모리에 값을 올리고 , 최신 값을 불러오는 역할을 한다.