관리 메뉴

sleepyotter

Interlocked 본문

프로그래밍/C# 게임서버

Interlocked

sleepyotter. 2021. 9. 7. 19:53
for(int i=0; i<100000; ++i)
{
    number++;
}

for(int i=0; i<100000; --i)
{
    number--;
}

2개의 for문을 2개의 스레드에서 동시에 시작한 후에 작업이 끝난 후 number를 출력해보면 0이 나오지 않는다.

number++ 하는 부분은 실제로는 3단계로 이루어진다.

1. number의 값을 추출하여 다른 곳에 저장

2. 다른 곳에 저장한 값을 1증가

3. number에 다른 곳에 저장한 값을 대입

그러면 ++ 하는 쪽에서는 1번을 이제야 막 했는데, -- 하는 쪽에서는 우연찮게 루프를 여러번 돌아서 -5를 했다고 하자.

그러면 0에서 시작했을 때, -5 상태인데, ++하는 쪽에서는 0에 +1을 한 다음에, 3번을 해서 1이 되버린다.

즉, -4가 되어야 하는데 1이 되버렸다.

따라서 중요한 점은 일련의 작업이 오롯이 한 번에 처리되던가, 그게 아니라면 실패를 해야 한다. 이를 원자성(Atomic)이라 한다.

경합 조건(Race Condition)

어떤 변수를 처리하려고  서로 막 달려드는 상태이다. Race Condition이 발생할 때에는 원자성이 보장되거나 Lock을 사용하지 않으면 의도한 결과가 나오지 않는다.

이를 위해, Interlocked가 c#에서 제공된다.

number++ 하는 부분은 아래와 같이 바꿀 수 있다.

Interlocked.Increment(ref number)

interlocked를 모르는 채로 보면 ref를 넘겨주기 때문에 위에 설명한 상황 처럼 --를 5번 해서 -5가 됐다고 쳐도 ++하려는 때에 해당하는 값에 +1 해주기 때문에 정상적으로 -4가 된다.

정확한 메커니즘은, 이에 접근한 순간 다른 녀석들은 이 값에 접근하지 못하도록 막고 내가 작업을 끝낸 후에야 다른 녀석들이 접근할 수 있게 하는 것이다. 또, 내부적으로 MemoryBarrier를 사용하기 때문에 volatile은 사용하지 않아도 된다.

 

'프로그래밍 > C# 게임서버' 카테고리의 다른 글

DeadLock  (0) 2021.09.07
Lock 기초  (0) 2021.09.07
메모리 배리어  (0) 2021.09.07
캐시 이론  (0) 2021.09.07
컴파일러 최적화  (0) 2021.09.07