8강 메모리 베리어
[1] 하드웨어 최적화
컴파일러도 최적화를 하지만, 하드웨어도 최적화를 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Program
{
static int x = 0;
static int y = 0;
static int r1 = 0;
static int r2 = 0;
//하드웨어 최적화
static void Thread_1() {
/*[1]*/y = 1; //store y
/*[2]*/r1 = x; // load x
}
static void Thread_2()
{
/*[3]*/x = 1; //store x
/*[4]*/r2 = y; //load y
}
static void Main(string[] args) {
int cnt = 0;
while (true)
{
cnt++;
x = y = r1 = r2 = 0; //모두 0을 넣는다
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
//이부분이 중요!
//[1][2][3][4] 경우를 순서대로 조합해보아도 둘다 0이 되는 경우는 존재하지 않는다!
//그러나 실행해보면 끝이난다
if (r1 == 0 && r2 == 0) break;
}
Console.WriteLine($"{cnt} 번 만에 빠져나옴");
}
}
- 2개의 스레드의 다음 코드
- [1]
y = 1;
- [2]
r1 = x;
- [3]
x = 1;
- [4]
r2 = y;
if (r1 == 0 && r2 == 0) break;
- [1][2][3][4] 경우를 순서대로 조합해보아도 둘다 0이 되는 경우는 존재하지 않지만, break로 종료가 된다!
⇒ 이유가 뭘까??
⇒ 하드웨어가 최적화를 하기 때문이다
하드웨어가 코드의 순서대로 실행하지 않고 스레드내의 코드의 순서를 바꾸기 때문이다
- 최적화의 코드의 순서
[2]
r1 = x;
4]
r2 = y;
👇
[1]
y = 1;
[3]
x = 1;
### Store과 Load
y = 1;
그냥 **실제 값을 넣는 것r1 = x;
변수에서 값을 끄집어 내는 것- x에서 값을 끄집어내서 할당하고 있음
[2] 메모리 베리어
[1] 하는 이유
- 코드 재배치 억제 ([1]과 같은 경우)
- 가시성이 좋다
[2] 메모리베리어 작동
메모리 베리어 하는 법
Thread.MemoryBarrier()
1
2
3
4
5
static void Thread_1() {
/*[1]*/y = 1; //store y
Thread.MemoryBarrier(); //메모리 베리어
/*[2]*/r1 = x; // load x
}
1
2
3
4
5
6
7
static void Thread_2()
{
/*[3]*/x = 1; //store x
Thread.MemoryBarrier(); //메모리 베리어
/*[4]*/
r2 = y; //load y
}
[3] 메모리 베리어의 종류
[1] Full Memory Barrier 🌟
- 메모리에서 Store , Load를 둘다 막는다
[2] Store Memory Barrier
- Store만 막는다
[3] Load Memory Barrier
- Load만 막는다
가시성 (메모리베리어의 작동 원리)
- 메모리 베리어는 가시성이 좋다
[1] 메모리 베리어의 역할
스토리 텔링으로
🧑직원이 주문 받은 내역을 🔖주문현황에 옮기고, 🧑🏻다른 직원이 그 주문현황을 바탕으로 자신의 📘수첩을 업데이트 하는 행위와 같다
⇒ 값을 최신의 값으로 따끈따근하게 💛업데이트💛 하는 것과 같다 (가시성에 도움!)
Thread.MemotyBarrier();
을 쓴 코드 윗단의 가시성을 보장한다
⇒ 정리하면, 메모리 베리어는 중앙 메모리에서 변수의 실제 현재 값을 가져오는 것이다
volatile
도 메모리 베리어 의 역할을 간접적으로 하고 있는 것이다- Lock, 아토믹도 간접적이다
메모리 베리어 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int ans;
bool complete;
void A(){
ans = 123;
Thread.MemoryBarrier();
complete = true;
Thread.MemotyBarrier();
}
void B(){
Thread.MemotyBarrier();
if(complete){
Thread.MemotyBarrier();
Console.WriteLine(ans);
}
}
complete = true; Thread.MemotyBarrier();
- 코드가 끝난 부분에도 메모리 베리어를 해줌으로써 가시성을 확실히 보장함
- 원하는 결과가 나올 것임
…