1. 프로그램과 프로세스
1.프로그램과 프로세스
프로세스
프로그램안에 들어 있는 명령어가 한 줄씩 실행되면서
프로그램이 무언가 활동하는 상태
멀티프로세싱
프로세스가 여러 개 실행되고 있는 것
2.스레드
스레드
프로세스처럼 명령어를 한줄씩 실행하는 기본단위
프로세스와의 차이점
한 프로세스에 여러 스레드가 존재한다.
같은 프로세스 내의 스레드들은 메모리공간을 같이 사용할 수 있음
싱글 스레드 프로그램
동시에 하나만 사용되는 프로그램
멀티스레딩
여러 스레드가 동시에 여러가지 일을 처리하게 하는 것.
3.멀티스레드 프로그래밍을 해야할 떄
오래 걸리는 일 하나와 빨리 끝나는 일 여럿을 같이 해야 할 때
게임프로그램에서 로딩할 때
어떤 긴 처리를 진행하는 동안 다른 짧은 일을 처리해야 할 때
플레이어 정보를 읽거나 쓰려고 디스크를 엑세스 하는경우
이 경우 CPU는 놀게된다.이 시간을 플레이어에게 분배하면 실행
서능을 개선할 수 있다.
기기에 있는 CPU를 모두 활용해야 할 때
4.스레드 정체
컨텍스트 스위치
프로세스 안에 있는 스레드들은 일정 시간마다 번갈아 가면서 실행을 한다.
각 스레드를 실행하다 말고 다른 스레드를마저 실행하는 과정.
컨텍스트 스위치는 적지않은 연산을 한다.
CPU 개수와 (Runnable)스레드 개수가 같거나 스레드 개수가 더 적으면
컨텍스트 스위치가 발생할 이유가 없다.
타임 슬라이스
컨텍스트 스위치 실행에서 '사람 입장에서 쾌적할 수 있는 가급적
긴시간 단위'
5.스레드를 다룰 때 주의 사항
데이터 레이스
두 스레드가 데이터에 접근해서 그 데이터 상태를 예측할 수 없게하는 것
컨텍스트 스위치에 의해 결과예측이 불가능한 상태.
트랜잭션
데이터베이스의 상태를 변화시키고 논리적 기능을 수행하기위한
작업단위 또는, 한꺼번에 모두 수행되어야 할 일련의 연산들이다
원자성
트랜잭션과 관련된 일은 모두 실행되거나 모두 실행되지 말아야 한다.
일관성
트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터
베이스 상태로 변환한다.
- 일관성이란 데이터 타입이 갑자기 바뀌지 않는다는 의미(ex int -> string)
원자성,일관성은 동기화를 통해 해결. 뮤텍스,잠금(Lock)의 방법 이용
독립성
트랜잭션을 수행하는 도중에 다른 연산작업이 끼어들지 못하게 한다.
지속성
성공적으로 트랜잭션이 수행되었다면, 그 결과는 완전히 반영이 되어야한다.
Commit을 하면 현재 상태는 영원히 보장된다
6.임계 영역과 뮤텍스
뮤텍스란 ?
상호 배제(mutual exclusion)의 줄임말
임계 영역(critical section)이라고도 한다.
lock_guard
- C++에서 뮤텍스 잠금 상태를 로컬 변수로 저장하고, 그 변수가 사라질 때
자동으로 잠금 해제가 되게 하는 클래스
- 예외 발생시 unlock이 되지 않는 상태를 해결해 준다.
- c#은 lock keyword로 해결한다.
메모리 바운드 시간
메모리에 접근하는 시간
7.교착 상태
교착상태란?
두 스레드가 서로를 기다리는 상황을 의미한다.
교착상태에서 발생하는 현상
- CPU 사용량이 현저히 낮거나 0%
- 클라이언트가 서버를 이용할 수 없다.
8.잠금 순서의 규칙
거꾸로만 잠그지 마라!
잠금순서와 같은 순거로 잠금을 해제하라
잠금순서를 정했다면 어떤 곳에서도 그 순서를 지켜야함.
하나의 스레드 안에서 여러 원자들에 대해 따로 잠금을 해야하는 경우
그 순서는 모든 스레드에서 동일하게 적용되어야 한다.
재귀 뮤텍스란?
한 스레드가 뮤텍스를 여러 번 반복해서 잠그는 것을 원할하게 처리해 줌
9.병렬성과 시리얼 병목
병렬성
여러 CPU가 각 스레드의 연산을 실행하여 동시 처리량을 올리는 것
시리얼병목
병렬로 실행되게 프로그램을 만들었는데 정작 한 CPU만 연산을 수행하는 현상
암달의 저주
CPU 개수가 많을수록 총 처리 효율성이 떨어지는 현상
시리얼 병목이 발생하는 구간을 최소로 해야한다.
디바이스타임
기기에 있는 장치(네트워크 인터페이스,디스크 등)에 뭔가를 요청해서
결과가 올 때까지 기다리는 시간
CPU가 연산을 하지않으며 자기 떄문에 시간을 낭비한다.
잠금하고나서 디바이스 타임을 갖지 말자. 시리얼 병목이 발생한다.
10.싱글스레드 게임 서버
싱글스레드 서버를 구동하는 경우 CPU 개수만큼 프로세스를 띄우는 것이
일반적이다.
싱글스레드로 서버를 만드는 경우, 디스크에서 플레이어 정보를 로딩할 때
발생하는 디바이스 타임을 처리하는 과정에서 큰 시리얼 병목이 일어난다.
11.멀티스레드 게임 서버
서버 프로세스를 많이 띄우기 곤란할 때.예를 들어 프로세스당 로딩해야 하는
게임 정보의 용량이 매우 클 때(MMO, 맵 로딩)
서로 다른 방이 같은 메모리 공간을 엑세스해야 할 때
보통 방 단위로 잠금 범위를 설정하는 것이 적당하다.
12.스레드 풀링
스레드 개수가 많을 때 발생하는 문제
- 호출 스택에 따른 메모리의 낭비
- 심각하게 발생하는 컨텍스트 스위치 현상
스레드 풀링
미리 쓰레드를 할당시켜 놓고 사용하는 기법. 이벤트가 발생하게 되면 노는 스레드를 찾아서 처리하고, 모든 스레드가 사용중이면 스레드가 사용 가능해 질 때까지 기다리게 된다.
13.이벤트
잠자는 스레드를 깨우는 도구. 스레드가 서로 소통해야하는 상황에 유리.
Reset
이벤트가 없음. 정수 값으로 0으로 표현됨
Set
이벤트가 있음. 정수 값으로 1으로 표현됨
자동 이벤트 모드
이벤트 신호를 가질 때, 이벤트를 기다리던 스레드가 있으면 그 스레드를 꺠운다. 그리고 상태 값이 자동으로 0으로 바뀐다.
여러 스레드 중 한 스레드만 꺠어남.
수동 이벤트 모드
이벤트 신호를 가질 때, 이벤트를 기다리던 스레드가 있으면 그 스레드를 꺠운다. 상태값은 여전히 1이고, 이를 0으로 바꾸는 것은 수동으로 해결해야 한다.
모든 스레드가 다 깨어남.
맥박 기능
- 이벤트 상태값을 0으로 바꾸는 것은 모든 스레드가 이벤트 대기에서 깨어난
이후에만 할 수 있는데, 그 시점을 알 수 없음.
- 딱 1회만 상태 값을 1로 바꾸고 즉시 다시 0으로 바꾸는 기능
14.셰마포어
뮤텍스나 임계 영역은 오로지 스레드 1개만 자원을 엑세스 할 수 있다.
셰마포어는 원하는 개수의 스레드가 자원을 엑세스 할 수 있게 한다.
멀티 스레드는 컨텍스트 스위치에 의해 정상적인 순서를 벗어나는 행동을 할 수 있다.
컨텍스트 스위치에 의해 스레드간 조건이 성립 안해 무한 루프가 도는 것을 방지하여
이벤트의 상태가 1,0 뿐만 아니라 그 이상의 값도 가지게 할 수 있게 하는 것.
(event는 돌발 상황에 의해 값이 2나 그 이상이 넘어가면 처리를 못함)
15.원자 조작
뮤텍스나 임계 영역 잠금 없이도 여러 스레드가 안전하게 접근할 수 있는것.
하드웨어 기능이다.
volatile
이 변수는 여러 스레드에서 언제든지 엑세스 한다는 의미.
원자성을 가진 값 더하기
int r = AtomicAdd(&a,3)
우리가 원하는 것은 a에 정확히 3이라는 값이 추가되는 것이다.
원자성을 가진 값 맞 바꾸기
int r = AtomicExchange(&a,10)
a의 과거 값이 r로 채워지고, a에는 10이 들어간다
원자성을 가진 조건부 값 맞바꾸기
int r = AtomicCompareExchange(&a,10,100);
리턴 값은 a를 바꾸기 전 값이다
16.팁
잠금 하나로 모든 멤버 변수를 보호하자
임계 영역이 많으면 유지 보수하기 어렵다.
어떤 멤버 변수를 엑세스하는 동안 많은 연산량이나 디바이스 타임이 있을 때는
잠금을 둘 이상으로 쪼갤 필요가 있다.
잠금의 전염성으로 발생한 실수
잠금으로 보호되는 리소스에서 얻어 온 값이나 포인터 주소 값 등이
로컬 변수로 있는 경우에도 잠금 상태를 계속 유지하는 것.(unlock을 걸지 않는다)
'게임 서버 프로그래밍 > 게임 서버 프로그래밍 교과서' 카테고리의 다른 글
#6. 프라우드넷 (0) | 2020.02.17 |
---|---|
#5. 게임 네트워크 (0) | 2020.02.17 |
#4. 게임 서버와 클라이언트 (0) | 2020.02.17 |
#3. 소켓 프로그래밍 (0) | 2020.02.17 |
#2. 컴퓨터 네트워크 (0) | 2020.02.17 |