C#/네트워크

[C#][서버] 메모리 배리어

goliot 2024. 6. 1. 16:44
반응형

메모리 최적화 예시

static int x = 0;
static int y = 0;
static int r1 = 0;
static int r2 = 0;

static void Thread_1()
{
    y = 1;
    r1 = x;
}

static void Thread_2()
{
    x = 1;
    r2 = 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}번 만에 빠져나옴");
}
  • 다음 코드를 실행하면, while이 빠져나와질까?

  • 놀랍게도 빠져나와진다!
  • 하드웨어도 최적화를 하고 있기 때문이다
    • x = 1과 r2 = y가 아무런 관련이 없기 때문에, 하드웨어가 마음대로 실행 순서를 바꾼 것
    • 싱글 쓰레드 환경에선 문제가 없지만, 멀티 쓰레드에선 문제가 됨

메모리 배리어

코드 재배치 억제

static void Thread_1()
{
    y = 1; //w
    Thread.MemoryBarrier(); //코드 사이에 장벽을 설정해서, 순서 바꾸지 말라고 강제
    r1 = x; //r
}

static void Thread_2()
{
    x = 1; //w
    Thread.MemoryBarrier();
    r2 = y; //r
}
  • 다음과 같이 Thread.MemoryBarrier()를 활용하여, 코드의 순서를 바꾸지 못하도록 강제할 수 있음
    • Store/Load 모두 막는다

가시성

  • 1번 직원이 주문을 받은 것을, 다른 직원들도 볼 수 있나?
    • 즉, 주문 현황에 주문 받은것을 저장해야함
    • 다른 직원들은, 주문현황에서 가져와야 함
  • MemoryBarrier가 가시성도 해결해준다!
    • 순서 억제 뿐 아니라 바로바로 주문현황에 올려줌
  • MemoryBarrier는 아토믹이나 락 등에 내부적으로 구현된 경우가 많음

다른 예제

int _answer;
bool _complete;

void A()
{
    _answer = 123; //w
    Thread.MemoryBarrier();
    _complete = true; //w
    Thread.MemoryBarrier();
}

void B()
{
    Thread.MemoryBarrier();
    if(_complete)
    {
        Thread.MemoryBarrier(); 
        Console.WriteLine(_answer); //r
    }
}
  • 마지막과 처음의 메모리 배리어는 무엇인가?
  • 이번에는 store가 연속적으로 두 번 일어남
    • 쓸 때마다, 동기화 작업을 직접 해주는 것
  • B에서는 읽기 전에 일단 동기화를 하고
    • if문 안에서도 읽기 전에 동기화 먼저 확실하게 해주고 WriteLine을 진행하는 것
반응형

'C# > 네트워크' 카테고리의 다른 글

[C#][서버] Lock 기초  (0) 2024.06.02
[C#][서버] Interlocked  (0) 2024.06.01
[C#][서버] 캐시 이론  (0) 2024.05.31
[C#][서버] 기본 멀티쓰레드 프로그래밍  (0) 2024.05.30
[C#][서버] 서버 개론, 멀티쓰레드 개론  (0) 2024.05.30