스레드란 무엇인가?
프로세스 안에서 실제로 코드를 실행하는 흐름
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
Process(프로세스)가 메모리와 파일 같은 자원을 담는 그릇이라면, Thread(스레드)는 그 안에서 실제로 명령어를 실행하는 흐름이다.
프로세스가 생성되면 보통 하나의 메인 스레드가 시작되고, 필요하면 추가 스레드를 만들 수 있다.
같은 프로세스의 스레드는 자원을 공유한다
같은 프로세스에 속한 스레드는 코드, 전역 데이터, 힙, 열린 파일을 공유한다. 대신 각 스레드는 자신의 Stack, 레지스터 상태, 실행 위치를 가진다.
하나의 프로세스
┌──────────────────────────┐
│ Code / Data / Heap 공유 │
├────────────┬─────────────┤
│ Thread A │ Thread B │
│ Stack A │ Stack B │
│ Register A │ Register B │
└────────────┴─────────────┘
두 스레드가 같은 객체의 주소를 사용할 수 있는 이유는 힙을 공유하기 때문이다. 반면 함수의 지역 변수는 기본적으로 각 스레드의 스택에 생기므로 서로 분리된다.
왜 스레드를 사용하는가?
게임을 예로 들면 메인 스레드가 입력과 화면 갱신을 처리하는 동안 작업 스레드가 경로 탐색이나 리소스 로딩을 할 수 있다. CPU 코어가 여러 개라면 서로 다른 스레드가 실제로 동시에 실행될 수도 있다.
std::thread worker([]()
{
LoadResources();
});
UpdateGame();
worker.join();
join()은 작업 스레드가 끝날 때까지 현재 스레드가 기다리게 한다.
프로세스와 스레드의 차이
프로세스는 기본적으로 메모리가 격리되어 있어 한 프로세스의 문제가 다른 프로세스로 바로 퍼지기 어렵다. 하지만 생성과 통신 비용이 비교적 크다.
스레드는 같은 메모리를 공유하므로 데이터를 주고받기 쉽고 비교적 가볍다. 대신 잘못된 포인터 접근이나 동기화 버그가 같은 프로세스 전체를 망가뜨릴 수 있다.
프로세스: 자원 소유와 격리의 단위
스레드: CPU가 실행하는 흐름의 단위
스레드가 많다고 무조건 빨라지지는 않는다. 작업을 나누는 비용, 락 대기, 캐시 충돌, 문맥 교환 비용이 계산 이득보다 커지면 오히려 느려질 수 있다.