Interlocked
Interlocked는 쓰레드를 사용할 때 변수의 원자성 1을 보존해주는 명령어다.
변수의 원자성이란 다음 코드를 보면서 알아보자.
static int number = 0;
static void Thread_1()
{
for (int i = 0; i < 10000; i++)
number++;
}
static void Thread_2()
{
for (int i = 0; i < 10000; 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();
Console.WriteLine(number);
}
흐름을 보면 number라는 변수가 있고,
2개의 쓰레드에서 number에 접근해 하나는 값을 하나씩 올리고, 하나는 값을 하나씩 내리는 코드다.
만번 씩 값을 오르내리는 정도는 문제 없지만 해당 변수에 여러 쓰레드가 기하급수적으로 많이 접근하게 되면 문제가 발생하게 된다.
여러 쓰레드가 하나의 메모리에 동시에 접근하여 값이 꼬이는 현상이 바로 경합조건이다.
이런 경합 조건이 발생하는 걸 막기 위해 Interlocked라는, 원자성을 보존해주는 클래스가 등장하게 된다.
우선 증감 연산자는 원자성을 보존해주는 연산자가 아니다.
우리가 보는 코드 상에는 단순히 ++, --로 끝나지만 실제로는
int tmp = number; // 해당 변수의 레지스터에서 값을 불러옴
tmp += 1; // 값에다가 +1 연산해주기
nubmer = tmp; // 다시 레지스터에 변한 값을 저장
이런 3가지 과정을 거쳐야 한다.
그렇기 때문에 3번 과정이 일어나려고 할 때 다른 쓰레드가 접근해버리면 의도한 결과와는 다른 값이 나오게 된다.
Interlocked는 레지스터 주소값에 직접 접근해 값을 바꿔버리기 때문에 과정이 하나 밖에 안 일어나고 원자성이 보장된다.
static int number = 0;
static void Thread_1()
{
for (int i = 0; i < 100000; i++)
{
Interlocked.Increment(ref number);
}
}
static void Thread_2()
{
for (int i = 0; i < 100000; i++)
{
Interlocked.Decrement(ref number);
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll();
Console.WriteLine(number);
}
Interlocked 클래스에서 제공하는 변수는 정수 밖에 없으니 유의해서 사용하자.
https://learn.microsoft.com/ko-kr/dotnet/api/system.threading.interlocked?view=net-7.0#methods
Interlocked 클래스 (System.Threading)
다중 스레드에서 공유하는 변수에 대한 원자 단위 연산을 제공합니다.
learn.microsoft.com
- 어떤 것이 더이상 쪼개질 수 없는 성질 [본문으로]
'공부 > 게임서버' 카테고리의 다른 글
게임 서버 이론 구현 #4 - SpinLock (0) | 2023.07.30 |
---|---|
게임 서버 이론 구현 #3 - Lock (0) | 2023.07.29 |
게임 서버 이론 구현 #1 - 컴파일러 최적화, 캐시 이론, 메모리 배리어 (0) | 2023.07.25 |
C# Thread 파해쳐보기 (0) | 2023.07.23 |
게임 서버 이론 (0) | 2023.07.23 |