1.4 스레드 정체

CPU 개수와 Runnable 스레드 개수가 같거나 Runnable 스레드 개수가 더 적으면 컨텍스트 스위치가 발생할 이유가 없다. 하지만 Runnable 스레드 개수가 더 많으면 컨텍스트 스위치가 어느 CPU 안에서는 반드시 발생한다. (비둘기집 원리)

 

멀티스레딩을 사용하여 소수 구하기

1 ~ 150000 사이의 소수들을 찾는 프로그램

멀티 스레드를 활용하지 않았을 때
4개의 스레드를 활용할 때

 

1.8 잠금 순서의 규칙

 

여러 뮤텍스를 사용할 때 교착 상태를 예방하려면 각 뮤텍스의 잠금 순서를 먼저 그래프로 그려 두고, 잠금을 할 때 잠금 순서 그래프를 보면서 거꾸로 잠근 것이 없는지 체크해야 한다.

 

재귀 뮤텍스

ㄴ 한 스레드가 같은 뮤텍스를 여러 번 반복해서 잠궈도 된다. 물론 잠금 횟수만큼 풀어야 한다.(재귀 잠금이 가능하다.)

ㄴ 재귀 잠금은 잠금 순서 그래프에 상관 없이 교착 상태를 일으키지 않는다. (첫 잠금에서만 순서를 지키면 된다)

 

1.9 병렬성과 시리얼 병목

여러 CPU가 각 스레드의 연산을 싫애하여 동시 처리량을 올리는 것을 병렬성이라고 한다. 병렬로 실행되게 프로그램을 만들었는데 정작 한 CPU만 연산을 수행하는 현상을 시리얼 병목이라고 한다.

 

 

시리얼 병목이 있을 때 CPU 개수가 많을수록 총 처리 효율성이 떨어지는 현상을 암달의 법칙(Amdahl's Law)라고 한다.

 

Visual Studio의 Concurrency Visualizer도구

ㄴ 멀티 스레드 프로그램이 병렬적으로 여러가지 일들을 동시에 잘 수행하는지 분석하여 시각화해서 보여주는 도구

 

 

https://marketplace.visualstudio.com/itemsitemName=Diagnostics.DiagnosticsConcurrencyVisualizer2019#overview

 

4개의 스레드를 사용한 프로그램을 분석한 경우

1.10 싱글 스레드 게임 서버

 

1.11 멀티 스레드 게임 서버

 

1.12 스레드 풀링

처리할 이벤트를 큐에 쌓아두고 비어 있는 스레드에 이벤트를 처리하도록 배분하는 방식이다.

스레드 개수를 클라이언트 개수만큼 두지 않고 스레드 풀링을 사용한다.

 

CPU 코어가 8개 있는 8개의 스레드를 실행시키는 상황에서 스레드가 CPU 연산만 하는 것이 아니라 데이터베이스나 파일 등에 액세스하는 스레드여서 CPU 사용율이 25%이고 디바이스 타임이 75%인 상황이라면 스레드 풀의스레드의 갯수를 4배 늘려 CPU를 놀게 하지 않게 해야 한다.

 

CPU 연산이 주 역할인 서버의 스레드 풀의 스레드 개수는 서버의 CPU 코어 개수와 동일하게 잡아도 충분하다.

 

1.13 이벤트

잠자는 스레드를 깨우는 도구로써 사용된다.

event는 내부적으로 0과 1의 상태 값을 가진다. (이벤트가 없으면 0 있으면 1)

 

윈도우 API에 이벤트 관련 함수가 있다.

https://docs.microsoft.com/ko-kr/windows/win32/sync/using-event-objects

 

이벤트 개체 사용(동기화) - Win32 apps

애플리케이션은 여러 상황에서 이벤트 개체를 사용하여 대기 스레드에 이벤트 발생을 알릴 수 있습니다.

docs.microsoft.com

 

자동 이벤트

ㄴ 이벤트 상태 값을 0으로 갖고 있다가 신호를 받으면(SetEvent) 상태 값이 1로 바뀌는데 이때 이벤트를 기다리던(잠들어 있던) 스레드 (Wait)가 있다면 그 스레드를 깨우고 자동으로 0의 상태 값으로 바뀐다.

ㄴ 두개 이상의 스레드를 이벤트를 기다리고 있었다면 여러 스레드중 하나만 깨어난다.

 

수동 이벤트

ㄴ 이벤트가 신호를 받으면 대기하고 있던 모든 스레드가 깨어난다.

ㄴ SetEvent()를 한 스레드에서 호출하면 대기하던 스레드에서 SetEvent(0)을 호출하여 수동으로 이벤트 상태 값을 되돌려줘야 한다. 하지만 이 방법을 사용하면 대기하던 스레드중 일부만 깨어날 가능성이 있다.

ㄴ PulseEvent()를 사용하여 이벤트에 신호를 주면 모든 스레드를 깨우면서 상태값을 자동으로 0으로 되돌려 준다.

 

1.14 세마포어

뮤텍스는 1개의 스레드만 자원을 액세스할 수 있게 하지만 세마포어는 원하는 개수의 스레드가 자원을 액세스할 수 있게 한다.

 

Wait() ~ Release() (mutex의 lock unlock같은 느낌)을 사용한다.

 

윈도우 API에 세마포어 관련 함수가 있다.

https://docs.microsoft.com/ko-kr/windows/win32/sync/using-semaphore-objects

 

세마포 개체 사용 - Win32 apps

다음 예제에서는 세마포 개체를 사용하여 특정 작업을 수행할 수 있는 스레드 수를 제한합니다.

docs.microsoft.com

 

스레드 간에 공유되는 큐가 있고 한 스레드는 큐에 항목을 넣고 다른 한 스레드는 큐에서 항목을 꺼내 쓰는 디자인에 활용하기 좋다.

 

초기값이 0인 세마포어를 만든 뒤, 항목을 넣는 스레드에서는 세마포어.Release()를 하면서 큐에 푸시하고 꺼내는 스레드에서는 Wait()를 하여 세마포어 값이 1 이상인 경우에만 큐에서 하나씩 요소를 꺼낸다.

 

1.15 원자 조작

원자 조작은 뮤텍스나 임계 영역 잠금 없이도 여러 스레드가 안전하게 변수에 접근할 수 있게 해준다.

32비트나 64비트 변수 타입에 여러 스레드가 접근할 때 한 스레드씩만 처리됨을 보장한다.

mutex보다 속도가 더 빠르다.

 

https://lemonyun.tistory.com/103

 

C++ memory order, atomic객체

atomic #include std::atomic counter(0); 여러 쓰레드에서 atomic 객체 자원을 수정할 때 원자적 연산(CPU가 명령어 한개로 처리하는 명령)을 사용하면 mutex를 사용하지 않아도 정상적인 결과가 나온다. memory..

lemonyun.tistory.com

 

'읽은 책 > 게임 서버 프로그래밍 교과서' 카테고리의 다른 글

3. 소켓 프로그래밍  (0) 2022.09.10
2. 컴퓨터 네트워크  (2) 2022.09.09

+ Recent posts