| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Tags
- JavaScript
- 트라이
- localstorage
- 그래프 탐색
- trie
- map
- 강한 연결 요소
- LCA
- 이분 탐색
- 분리 집합
- 게임 서버 아키텍처
- DP
- 벨만-포드
- R 그래프
- Spin Lock
- Strongly Connected Component
- Prisma
- Lock-free Stack
- 비트마스킹
- 2-SAT
- 최소 공통 조상
- SCC
- Binary Lifting
- ccw 알고리즘
- Github
- Behavior Design Pattern
- 비트필드를 이용한 dp
- PROJECT
- Express.js
- 자바스크립트
Archives
- Today
- Total
dh_0e
[C++/Game Server] Thread Manager (+각 서버 file 설명) 본문
Thread Manager
- 게임 서버나 대규모 시스템 프로그래밍에서 수많은 thread들을 효율적으로 관리하기 위한 지휘소 역할
- 주요 용도
- Thread 생성 및 생명주기 관리
- 서버가 시작될 때 필요한 스레드 개수(Worker Threads)를 한꺼번에 생성하고 관리함
- 각 스레드가 언제 시작되고 언제 안전하게 종료(Join)되어야 하는지를 제어하여 자원 누수를 방지함
- Thread 로컬 저장소(TLS) 초기화
- 각 스레드만이 가지는 고유한 데이터(ex ThreadId, 전용 메모리 풀)를 설정
- GThreadManager를 통해 현재 어떤 스레드가 어떤 역할을 수행 중인지 추적할 수 있게 도움
- 작업 분배 및 부하 분산 (Load Balancing)
- 수천 명의 유저 패킷이 들어왔을 때, 이를 어떤 스레드에게 맡길지 결정하는 로직을 포함할 수 있음
- 특정 스레드에만 작업이 몰리지 않도록 균형을 맞추는 역할을 수행
- Thread 생성 및 생명주기 관리

- 다음 파일들을 수정하여 스레드 매니저 생성
CoreGlobal
- 서버 엔진 전반에서 공통적으로 사용되는 전역 객체들을 한데 모아 관리하는 역할을 하는 파일
- 중앙 집중 관리: ThreadManager, MemoryManager, LogManager 등 엔진의 핵심 컴포넌트들을 어디서든 쉽게 접근할 수 있도록 포인터 형태로 모아둠
- 생명주기 제어: 서버가 켜질 때 전역 객체들을 순서에 맞게 생성(Init)하고, 서버가 꺼질 때 안전하게 소멸(Clear)시키는 주체
- CoreGlobal.h(선언부): 다른 모든 파일에서 이 전역 객체들의 존재를 알 수 있도록 외부 기호(extern)로 선언만 해둠
- CoreGlobal.cpp(정의부): 실제로 메모리 공간을 할당하고 전역 변수의 실체를 만듦


- 서버가 켜질 때 GThreadManager 포인터를 만들어 new로 생성하고, 서버가 꺼질 때 소멸시킴
CoreTls
- Thread Local Storage(TLS)를 관리하는 파일
- TLS: 전역 변수처럼 어디서든 접근할 수 있지만, 각 스레드마다 독립적인 메모리 공간을 갖게 하는 저장소
- 여러 스레드가 동시에 작동하는 서버 환경에서, 서로의 데이터를 침범하지 않고 "나만의 고유 데이터"를 유지하기 위해 사용
[C++/Game Server] Thread Local Storage
TLS(Thread Local Storage)전역 변수처럼 어디서든 접근할 수 있지만, 실제로는 각 스레드가 자신만의 독립적인 공간을 가지게 하는 기술스레드 별로 static 변수 선언을 할 수 있는 느낌스택 영역과 다
dh-0e.tistory.com
- 주요 용도
- 스레드 ID 관리: 현재 실행 중인 스레드가 몇 번 스레드인지(LThreadId) 저장하여 로그를 남기거나 작업을 구분
- 메모리 풀(Memory Pool): 매번 무거운 new/delete를 하는 대신, 각 스레드가 미리 할당받은 전용 메모리 바구니를 사용하여 성능을 극대화함
- 데드락 방지: 스레드마다 독립적인 자원을 가지게 함으로써 공유 자원에 대한 경쟁(Race Condition)을 줄임


- Header(.h): 외부 기호(extern)를 사용하여 다른 파일들에게 이 변수가 존재함을 알림
- CPP(.cpp): 실제 메모리 할당 및 초기화
Thread/ThreadManager
- 멀티스레드 서버 환경에서 스레드의 생성부터 종료까지의 모든 과정을 총괄하는 지휘소
- 주요 용도
- 스레드 생명주기 관리 (Launch & Join)
- Launch(생성): 새로운 스레드를 생성하고 실행할 함수(콜백)를 맡김
- Join(종료 대기): 서버가 종료될 때 실행 중인 모든 스레드가 안전하게 작업을 마칠 때까지 기다려줌
- TLS(Thread Local Storage) 초기화 및 해제
- initTLS: 스레드가 생성되자마자 실행되며, 해당 스레드 전용 메모리 풀이나 스레드 ID(LThreadId)를 초기화함
- DestroyTLS: 스레드 작업이 끝나면 할당했던 고유 자원들을 정리
- 스레드 안정성(Thread Safety) 확보
- 여러 스레드가 동시에 Launch를 호출해 스레드 목록(_thread 벡터)에 접근하면 충돌이 날 수 있으므로 lock 등을 사용하여 안정성 확보
- 스레드 생명주기 관리 (Launch & Join)
Header(선언부)

- 설계도 제공 및 존재 알림
- 클래스가 어떤 멤버 변수와 함수를 가지고 있는지 구조를 정의
CPP(구현부)

- 실제 기능 동작 및 메모리 할당
- ThreadManager() (생성자)
- 메인 스레드도 하나의 스레드로 간주하여, 프로그램 시작 시 메인 스레드 전용 TLS를 초기화(InitTLS())함
- 메인 스레드가 첫 번째 스레드이므로 ID 1을 부여받게 됨
- 메인 스레드도 하나의 스레드로 간주하여, 프로그램 시작 시 메인 스레드 전용 TLS를 초기화(InitTLS())함
- Launch(function<void(void)> callback)
- LockGuard를 사용해 여러 스레드가 동시에 스레드를 생성하려고 할 때, 스레드 목록(_threads) 데이터가 깨지지 않게 보호하며 새로운 스레드를 생성하여 목록에 추가함
- 람다를 사용하여 InitTLS(), DestroyTLS()를 callback 함수 직후에 실행하게끔 하여 스레드의 번호(ID)를 부여하고, 스레드 전용 자원을 정리하는 함수를 추가해 줌
- Join()
- 관리 중인 모든 스레드를 하나씩 확인하며 스레드가 아직 실행 중이라면(joinable 하면), 작업이 끝날 때까지 현재 스레드(메인 스레드)를 멈추고 기다림
- 모든 스레드가 종료되면 _threads 목록을 비움
- InitTLS()
- static으로 SthreadId라는 함수 전역적으로 관리되는 스레드 번호 생성기를 만듦
- Atomic으로도 선언하여 여러 스레드가 동시에 번호를 가져가도 중복되지 않게 함
- 현재 스레드에게 고유 번호를 부여하고, 다음 스레드를 위해 번호를 1 증가시킴
- 고유 번호는 각 스레드의 CoreTls 저장소에 개별적으로 저장
- Id를 1 증가시키는 SThreadId.fetch_add(1)은 SthreadId 값을 준 이후 1을 증가시키는 것과 마찬가지
- LthreadId = SthreadId++; 라고 생각하면 됨
- static으로 SthreadId라는 함수 전역적으로 관리되는 스레드 번호 생성기를 만듦
GameServer.cpp
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <atomic>
#include <mutex>
#include <Windows.h>
#include <future>
#include "ThreadManager.h"
#include <chrono>
CoreGlobal Core;
void ThreadMain()
{
while (1)
{
cout << "Hello! I am thread ..." << LThreadId << endl;
this_thread::sleep_for(1s);
}
}
int main()
{
for (int32 i = 0; i < 5; i++) {
GThreadManager->Launch(ThreadMain);
}
GThreadManager->Join();
return 0;
}
- 빌드 후 main을 다음처럼 실행하면 thread들이 다음과 같이 각 번호를 부여받고 while문을 돌고 있음

이외 파일들
- 서버 프로그래밍에서 공통적으로 사용되는 이 파일들은 코드의 생산성, 빌드 속도, 가독성을 위해 존재함
Types.h
- 용도: 기본 자료형의 재정의
- 역할: C++ 기본 자료형(int, short, unsigned long long 등)을 더 직관적으로 길이가 일정한 이름으로 재정의
- 장점: 플랫폼마다 크기가 달라질 수 있는 자료형을 고정하여 서버 시스템의 안정성을 높임

CorePch.h / CorePch.cpp
- 용도: 서버 엔진(Core) 레이어의 미리 컴파일된 헤더
- 역할: 엔진 프레임워크 수준에서 변하지 않는 라이브러리 헤더들(ex: <vector>, <list>, <thread>, <windows.h>)을 모아둠
- 내용: 위에서 설명한 Types.h, CoreMacro.h 등을 포함하여 엔진 전반에 쓰이는 기본 도구들을 한데 묶음


pch.h / pch.cpp (Precompiled Header)
- 용도: 현재 프로젝트(Server) 레이어의 미리 컴파일된 헤더
- 역할: 실제 서버 로직이 들어있는 프로젝트에서 빌드 속도를 높이기 위해 사용
- 관계: 보통 pch.h는 내부적으로 CorePch.h를 포함하고 있음
- 중요성: 자주 바뀌지 않는 거대한 헤더들을 미리 컴파일된 상태로 유지하여, 전체 빌드 시간을 수십 배 단축시킴


- 현재 ServerCore 내에 위치하고 있지만, 서버 로직을 짤 때 GameServer로 이동시킬 예정
CoreMacro.h
- 용도: 공통 매크로 정의
- 역할: 프로젝트 전역에서 반복적으로 사용되는 코드 패턴을 매크로 함수로 만들어 관리
- 장점: 복잡한 코드를 한 단어로 줄여 가독성을 높이고 오타를 방지함

- 다음과 같이 에러 체크용 ASSERT나 디버깅을 위해 CRASH를 유도하는 매크로 등을 미리 만들어 둘 수 있음
- 싱글톤 패턴 선언 매크로, 크리티컬 섹션을 제어하는 LOCK 관련 매크로 등도 만들어 놀 수 있음
'C++ > Game Server' 카테고리의 다른 글
| [C++/Game Server] Reader-Writer Lock (0) | 2026.02.12 |
|---|---|
| [C++/Game Server] Lock-Free Stack (with Smart Pointer, Reference Counting) (0) | 2026.02.10 |
| [C++/Game Server] Lock-Based Stack/Queue (+delete, IN/OUT) (0) | 2026.02.05 |
| [C++/Game Server] Thread Local Storage (0) | 2026.02.05 |
| [C++/Game Server] 동기화 방식과 메모리 정책 (memory_order) (1) | 2026.02.04 |