본문 바로가기

게임 회사/서버 프로그래밍

[1]스레드와 멀티 스레드

개인적으로 취업을 준비하면서 공부한 내용을 정리하는 목적입니다. 틀린 부분은 말씀 주세요.

 

프로그램(program) = 데이터(data) + 코드(code)

 

프로세스(process) = 컴퓨터 내에서 실행중인 프로그램의 상태

스레드(thread) = 프로세스 내에서 명령어를 한 줄씩 처리하는 기본 단위

 

process vs thread

- 스레드는 한 프로세스 안에 여러 개가 있음

- 한 프로세스 안에 있는 스레드들은 같은 메모리 공간을 사용할 수 있음

- 스레드마다 스택을 가짐(각 스레드에서 실행되는 함수의 로컬 변수들이 스레드마다 있음)

 

로딩 = 프로그램 내에 있는 코드와 데이터를 프로세스 메모리로 불러들임

 

호출 스택(call stack)

- 함수 호출(function call)을 추적할 때 사용, 함수 호출 당 하나씩의 스택들로 구성됨

- 자신을 호출했던 호출자(caller) 함수의 실행 지점으로 되돌아가야 하는데 이 주소를 기억

- 스택 = 지역 변수 + 함수로 들어온 인수 + 호출한 함수의 스택 정보 + 반환값 주소

 

메모리 구조

1) 코드 영역 : 실행할 프로그램의 코드

2) 데이터 영역 : 전역 변수, 정적 변수

3) 힙 영역 : 사용자의 동적 할당(런타임에 크기가 결정)

4) 스택 영역 : 지역 변수, 매개 변수(컴파일 타임에 크기가 결정)

 

멀티프로세싱(multi-processing) : 같은 프로그램을 동시에 여러 개를 실행

멀티스레드(multi-thread) : 여러 스레드가 여러 일을 처리하게 하는 것

 

멀티스레드 사용 시 주의 사항

- 메인 스레드(기본적으로 존재하는 스레드)가 종료되어도 다른 스레드는 남아서 무언가를 하고 있을 수 있음

- 이를 좀비 프로세스라고 함

 

C++에서 스레드 선언 방법

std::thread t1(ThreadProc, 123); // 함수명, 파라미터

 

멀티스레드 활용에 있어서 중요한 점

- 기기에 있는 CPU 활용을 모두 활용할 수 있음

스레드는 코어 하나만을 사용, 8코어 CPU여도 싱글스레드 사용한 프로그램이면 1코어만 사용

 

thread->join(); // 부모 스레드는 자식 스레드의 실행이 끝날 때까지 멈추게 됨

 

컨텍스트 스위치(context switch)

- 어떤 하나의 프로세스 실행 상태에서 다른 프로세스를 실행해야 할 때, 기존 프로세스의 상태 또는 값을 저장하고 다른 프로세스의 상태 또는 값을 교체하는 작업

- 멀티 스레드의 경우, 한 스레드의 실행을 멈추고 다른 스레드를 마저 실행하는 과정

- 컨텍스트 스위칭을 하는 과정도 자원이 들어가므로 잦은 컨텍스트 스위치는 비효율

- 컨텍스트 스위칭의 시간 단위는 타임 슬라이스(time slice)

 

멀티 스레드 시 주의 사항

- 원자성(atomicity) : 한 스레드가 변수를 건드리는 동안, 다른 스레드는 해당 변수에 접근할 수 없어야 함

- 일관성(consistency) : 변수의 상태가 항상 일관성 있게 유지됨

- 원자성과 일관성을 위해 동기화를 하며 이를 위한 것이 임계 영역(critical section)과 뮤텍스(mutex, 상호 배제), 잠금(lock, 뮤텍스에 대한 사용권을 얻는 과정)

 

컨텐션(Contention) : 두 스레드가 동시에 한 데이터를 액세스하려고 하는 상황

 

교착상태(deadlock)

- 두 개 이상의 작업이 상대방의 작업이 끝나기만을 기다려 결과적으로 아무런 작업도 완료되지 않은 상태

- 교착 상태 발생 조건 : 4가지 조건을 만족하면 교착 상태 발생

1) 상호 배제(mutual exclusion) : 자신이 필요로 하는 자원에 대한 베타적(독점) 사용을 요구

2) 점유와 대기(hold and wait) : 어떤 프로세스가 하나의 자원을 점유하면서 다른 프로세스가 점유한 자원을 요청

3) 비선점(no preemption) : 자원을 점유하고 작업이 끝났는데 자원을 반환하지 않는 경우

4) 환형 대기(circulat wait) : 양 스레드가 서로의 자원을 요구하면서 서로 반환을 안함

 

기아 상태(starvation) : 교착 상태 해결을 위한 protocol은 지켜지지만 계속 교착 상태인 경우

 

스레드 풀링(thread pooling)

- 서버 구현에 있어서 클라이언트 개수만큼 서버를 두는 일은 없음 : 스레드마다 호출 스택을 가짐에 따라 메모리 급증 + 컨텍스트 스위치 발생빈도가 높으면 효율이 떨어짐

- 이를 해결하기 위하여 스레드 풀링 사용

- 스레드 풀링은 스레드의 재활용, 할당된 일을 마친 스레드를 소멸시키지 않고 스레드 풀에 저장해뒀다가 필요할 때 다시 꺼내 씀(스레드의 생성과 소멸에 대한 비용을 지불하지 않음)

 

이벤트 : 잠자는 스레드를 깨우는 도구

- Reset(0) : 이벤트가 없음을 위미

- Set(1) : 이벤트가 있음을 의미

 

세마포어(semaphore)

- 공유된 자원의 데이터 혹은 임계 영역 등에 여러 프로세스 혹은 스레드가 접근하는 것을 막아줌(동기화 대상이 하나 이상, 즉 여러 개의 스레드가 정해진 개수만큼 접근 가능)

- 뮤텍스는 하나의 프로세스나 스레드가 접근하는 것을 막아줌(동기화 대상이 하나)

 

원자 조작(atomic operation)

- 뮤텍스나 임계 영역 잠금 없이도 여러 스레드가 안전하게 접근할 수 있는 것을 의미

- 하드웨어 기능이며 대부분 컴파일러는 원자 조작 기능을 쓸 수 있음

'게임 회사 > 서버 프로그래밍' 카테고리의 다른 글

[3] 소켓 프로그래밍  (0) 2022.06.01
[2] 컴퓨터 네트워크  (0) 2022.06.01