Home 8강 메모리 베리어
Post
Cancel

8강 메모리 베리어

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. 코드 재배치 억제 ([1]과 같은 경우)
  2. 가시성이 좋다

[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();
    • 코드가 끝난 부분에도 메모리 베리어를 해줌으로써 가시성을 확실히 보장함
    • 원하는 결과가 나올 것임

This post is licensed under CC BY 4.0 by the author.