Interlocked

Eunho Bae·2022년 2월 24일
0

경합조건 (Race Condition)

num++;는 다음과 같이 세 단계에 걸쳐 일어난다.

int temp = num;
temp += 1;
num = temp;

따라서 쓰레드가 두개있고 각각의 쓰레드에서 다음과 같은 코드를 수행하면

static int num = 0;

// 쓰레드1
for(int i=0; i<100000; i++)
	num++;

// 쓰레드2
for(int i=0; i<100000; i++)
	num--;

num의 결과값이 0이 아니게 된다.
왜냐하면 num이 바로 1씩 증가/감소하지 않고 세 단계를 거치기 때문에 그런것이다.

이해를 쉽게 하기 위해 i<100000가 아닌, i<1로 바꿔서 생각해보면
num++; 가 있는 쓰레드가 먼저 num = temp; 라인을 실행한다고 했을때
결과적으로 num의 값은 0이 아닌 -1이 되어버린다.

즉, num++ 3줄이 전부 실행된 후에 num-- 3줄이 실행되어야 0이 출력이 되는데,
2줄 실행되고 중간에 num--가 실행이 되면 문제가 생긴다고 할 수 있다.


원자성

더 이상 쪼개질 수 없는 최소 단위

원자성이 적용되지 않는다면 다음과 같은 참사가 발생할 수 있다.

  1. 유저2의 지갑에서 10억 메소를 차감한다.
  2. 집행검을 유저1의 인벤토리에서 뺀다.
  3. 집행검을 유저2의 인벤토리에 넣는다.

만약 1까지 수행한 후에 서버 크래시가 일어난다면, 10억메소와 함께 집행검이 사라지는 대참사가 발생하게 될 것이다.

Interlocked.Increment/.Decrement(ref num);
// Increments a specified variable and stores the result, as an atomic operation.
// 즉 원자적으로 일을 처리한다는 뜻

그래서 num++이 바로 1증가시키도록 하기 위해 위 함수를 사용할 수 있다.
하지만 성능상 문제가 있다.


lock

lock() {}은 블록단위로 원자성을 보장해준다.
lock()은 내부적으로 Monitor.Enter(); Monitor.Exit();로 구현이 되어 있으니 lock을 쓰도록 하자

profile
개인 공부 정리

0개의 댓글

관련 채용 정보