[Server Programming/cpp] Atomic

thread를 사용할때 전역 변수 공유 문제점

// GameServer.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <thread>

int32 sum = 0;

void Add() {
	for (int32 i = 0; i < 100'0000; i++) {
		sum++;
	}
}

void Sub() {
	for (int32 i = 0; i < 100'0000; i++)
	{
		sum--;
	}
}

int main()
{
	std::thread t1(Add);
	std::thread t2(Sub);
	t1.join();
	t2.join();

	cout << sum << endl;
}	
결과값이 할때마다 제각각이다.

실제로 sum++이 컴퓨터에서 동작할때 약식으로 아래와 같은 일이 일어난다.

int32 eax = sum;
eax = eax + 1;
sum = eax;

sum--

int32 eax = sum;
eax = eax - 1;
sum = eax;

두 스레드가 각각 동작을 할때 위의 과정이 거의 랜덤으로 각 줄이 실행될 것이다. 그렇다면 한쪽에서 진행하더라도 다른 한쪽에서 sum에 자기 결과값을 최종적으로 넣는다던지..

여러 과정이 섞이고 그게 몇만번 반복되어 엉뚱한 숫자가 등장하게 되는 것.

해결법? Atomic을 이용해서 동기화

위에서 살펴본 sum++의 같은시간에 세가지 과정이 한번에 일어난다면?

깔끔하게 결과값을 적용하여 변경할것이다!

이를 동기화한다고 하며, 그 동기화 기법 중 atomic을 사용해보자.

*atomic: all or nothing (원자성)

#include <atomic>

...

atomic<int32> sum = 0;

...
sum.fetch_add(1); //sum++와 결과가 같지만 atomic을 적용한 변수임을 특정

atomic 결론

  • 동기화를 통해 상수적인 결과를 얻을 수 있다.
  • 추가 연산으로 속도 저하 발생 가능성 -> 꼭 필요한 경우에만 사용

출처

인프런 Rookiss, "[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버"