공유 자원의 문제
#include <iostream>
#include <thread>
int32 sum = 0;
void Add()
{
for (int32 i = 0; i < 1'000'000; i++)
{
sum++;
}
}
void Sub()
{
for (int32 i = 0; i < 1'000'000; i++)
{
sum--;
}
}
int main()
{
std::thread t1(Add);
std::thread t2(Sub);
t1.join();
t2.join();
cout << sum << endl;
}
위의 코드처럼
두 스레드에 각각 더하기와 빼기를 실행시키면
결과는 0이 아닌 이상한 값이 나온다
조금 더 정확하게 코드를 살펴보면
사실 sum++ 코드는 사실 한 줄로 작성된 코드이지만
실제로 어셈블리어를 확인해보면
아래의 코드처럼
사실 3단계의 과정으로 이루어져 있다
sum++;
// 실제 내부 동작
int32 eax = sum;
eax = eax + 1;
sum = eax;
따라서 더하기와 빼기가 한 사이클 동작하는 예시를
아래의 코드를 통해 알아보자
int32 sum = 0;
void Add()
{
for (int32 i = 0; i < 1'000'000; i++)
{
//sum++;
int32 eax = sum;// 1) eax: 0 sum: 0
eax = eax + 1;// 3) eax: 1 sum: 0
sum = eax;// 4) eax: 1 sum: 1
}
}
void Sub()
{
for (int32 i = 0; i < 1'000'000; i++)
{
//sum--;
int32 eax = sum;// 2) eax: 0 sum: 0
eax = eax - 1;// 5) eax: -1 sum: 0
sum = eax;// 6) eax: -1 sum: -1
}
}
위의 코드 순서처럼 한 사이클이 동작한다면
분명 Add가 한번 Sub가 한번 진행되었지만
최종적으로 sum에는 0이 아닌 -1이 저장된다
이처럼 공유자원을 여러 스레드에서 접근을 하면
문제가 발생한다
Atomic
위의 문제를 해결하는 한 가지 방법 중 Atomic이 있다
공유자원 변수에 Atomic을 사용하면,
해당 변수에 대해 다른 스레드가 작업을 한다면
그 작업이 끝날 때까지 기다린다
따라서 Add 중에는 Sub를 기다리고
Sub 중에는 Add를 기다리기에 서로 침범하지 않는다는 것이다
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <thread>
#include <atomic>
atomic<int32> sum = 0;
void Add()
{
for (int32 i = 0; i < 1'000'000; i++)
{
//sum++;
sum.fetch_add(1);
}
}
void Sub()
{
for (int32 i = 0; i < 1'000'000; i++)
{
//sum--;
sum.fetch_add(-1);
}
}
int main()
{
std::thread t1(Add);
std::thread t2(Sub);
t1.join();
t2.join();
cout << sum << endl;// 0 출력
}
'게임 서버' 카테고리의 다른 글
[게임서버 섹션2 Note] DeadLock (0) | 2024.12.29 |
---|---|
[게임서버 섹션2 Note] Lock 기초 (0) | 2024.12.28 |
[게임서버 섹션2 Note] 스레드 생성 (0) | 2024.12.28 |
[게임서버 섹션2 Note] 멀티스레드 개론 (0) | 2024.12.28 |
[게임서버 섹션1 Note] 환경 설정 (0) | 2024.12.28 |