전 글에서 프로세스와 쓰레드의 차이점을 정리해보았다.

 

예제 코드를 작성해보자

#include "pch.h"
#include <iostream>
#include <thread>

static int tempNum = 0;

void Add()
{
	for (int i = 0; i < 1000000; i++)
	{
		tempNum++;
	}
}


void Sub()
{
	for (int i = 0; i < 1000000; i++)
	{
		tempNum--;
	}
}

int main()
{
	cout << tempNum << endl;

	std::thread t1(Add);
	std::thread t2(Sub);
	t1.join();
	t2.join();
	cout << tempNum << endl;
}

 

 

static int tempNum = 0;
//tempNum이라는 전역변수를 0으로 초기화하고

 

cout << tempNum << endl;

//0으로 초기화된 tempNum 출력

 

std::thread t1(Add);
std::thread t2(Sub);

//tempNum을 백만번 증가시키는 쓰레드를 실행

//tempNum을 백만번 감소시키는 쓰레드를 실행

 

t1.join();
t2.join();

//t1 쓰레드가 종료될때까지 대기

//t2 쓰레드가 종료될때까지 대기

 

cout << tempNum << endl

쓰레드 실행이 완료된 상태에서 tempNum출력 

 

결과는 어떻게 나올까?

0으로초기화하고

백만번더하면서 백만번을빼니까 정답은 0??

실제로 결과값은 0이 나오지않는다.

심지어 실행할때마다 결과값은 다르게 출력된다.

 

왜 이렇게될까?


 

실제로 백만번 1씩 증가시키는 부분의 어셈블리코드는 보면 위와같다

 

00007FF6EB922515  mov         eax,dword ptr [tempNum (07FF6EB92F440h)]  

//07FF6EB92F440h 의 주소에있는 데이터를 eax로 이동


00007FF6EB92251B  inc         eax  

//eax값을 증가


00007FF6EB92251D  mov         dword ptr [tempNum (07FF6EB92F440h)],eax  

//증가된 eax값을 다시 07FF6EB92F440h주소로 이동

 

우리가 코드를 작성할때에는 한줄로 tempNum++ 한줄로 표현하지만

 

실제로 코드가 돌아갈때에는

 

메모리에서 -> CPU로 값을 이동하고 -> 연산을 한 후에 -> 다시 CPU로 이동을 하는 행위를한다.

 

그럼 다시 쓰레드가 돌아가는 상황을 생각해보자

 

tempNum은 0이다.

 

Add thread> tempNum에 있는 데이터를 CPU a위치로 옮겼다. 옮겨진 값은 0이다.

Sub thread> tempNum에있는 데이터를 CPU b위치로 옮겼다. 옮겨진 값은 0이다.

 

Add thread> a위치의 값을 +1했다 연산된 값은 +1이다
Sub thread> b위치의 값을 -1했다 연산된 값은 -1이다

 

Add thread> +1된 데이터를 다시 tempNum 메모리 위치로 옮긴다. tempNum은 +1이다
Sub thread> -된 데이터를 다시 tempNum 메모리 위치로 옮긴다. tempNum은 -1이된다.

 

위 스탭은 예시이다 실제로 저렇게 드라마틱하게 한단계씩 실행되지는않는다.

위 예시에서 중요한점은

Add Thread에서 연산된값은 Sub쓰레드에서 연산된 값으로 덮혔다는것이다.

 

위와같은 행위가 계속 반복되면서

백만번 더하고 백만번 빼는것같지만 0이라는 결과값이 나오지 않는것이다.

 

위와같은 행위를 해결할 수 있는 방법이 동기화이다.

 

다음글에서 설명이어서 하겠습니다.

 

 

 

'게임 프로그래밍 > WINDOW SERVER' 카테고리의 다른 글

Atomic  (0) 2025.02.25
프로세스? 쓰레드?  (0) 2025.02.25

+ Recent posts