반응형
문제 상황
static void Thread_1()
{
for(int i=0; i<100000; i++)
number++;
}
static void Thread_2()
{
for (int i = 0; i < 100000; i++)
number--;
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(number);
}
- 다음을 실행하면, 10만번 더하고, 10만번 뺐으니까 0이 출력돼야겠지만?
- 이렇게 이상한 값이 출력된다.
이유
- 우선 ++, -- 연산은 내부적으로 다음과 같이 처리된다.
int temp = number; // 0
temp += 1; // 1
number = temp; // number = 1
int temp = number; // 0
temp -= 1; // -1
number = temp; //number = -1;
- 이렇게 세 줄이 모두 실행되기 전에 다른 쓰레드에서 number를 수정해 버린다면?
- number = 1 -> number = -1 로 점프해버리는 상황이 발생한다.
- 게임에서 예시를 들면
- 돈 -= 100
- 서버 다운 -> 이러면 돈만 먹고 아이템이 들어오지 않는 상황이 발생한다.
- 인벤토리 += 아이템
Race Condition
- 열정이 넘치는 세 직원이 있고, 주문을 자기가 처리하려고 안달이 나있다.
- 한 테이블에서 콜라 하나 주문이 들어왔다.
- 세 직원이 모두 각자 콜라를 하나씩 들고 그 테이블로 전달했다.
- 이런 상황이 발생하는 것이 Race Condition
InterLock
- 이것을 해결하기 위해 ++, -- 대신 이것을 사용해보자
Interlocked.Increment(ref number);
Interlocked.Decrement(ref number);
//ref는 c언어의 포인터처럼 직접 메모리에 접근해 작업을 수행한다는 의미로 보면 된다,
- 이러면 All or Nothing으로 원자적으로 모든 연산이 끝날 때 까지 number의 소유권을 갖게 되는 것이다.
- Race Condition 문제를 해결
연산이 끝난 값을 그대로 가져오고 싶다면?
int after = number;
Interlocked.Increment(ref number);
after = number;
- 이렇게 하면 2 -> 3번째 줄로 넘어가는 사이에 number가 바뀔 수 있다.
- 대신 Increment 함수에는 리턴값이 존재하여 다음과같이 사용하면 된다.
int after = Interlocked.Increment(ref number);
- 이렇게 하면 연산이 끝난 값을 그대로 가져오게 된다.
반응형
'C# > 네트워크' 카테고리의 다른 글
[c#][서버] 데드락 (0) | 2024.06.02 |
---|---|
[C#][서버] Lock 기초 (0) | 2024.06.02 |
[C#][서버] 메모리 배리어 (0) | 2024.06.01 |
[C#][서버] 캐시 이론 (0) | 2024.05.31 |
[C#][서버] 기본 멀티쓰레드 프로그래밍 (0) | 2024.05.30 |