Thread (스레드)는 프로세스 (Process)가 할당받은 자원을 이용하는 “작업 흐름”의 단위이다.

따라서 스레드는 프로세스 내에 여러 개 존재할 수 있으며,
프로세스의 자원에 접근하여 작업을 수행한다.

여기서 의문이 생긴다.
프로세스 하나가 하나의 작업 흐름을 가지고 실행하면 되는데,
왜 스레드를 사용해서 작업 흐름을 여러 개로 만들까?

프로세스는 하나의 작은 운영체제라고 볼 수 있다.
따라서 프로세스 당 실행 흐름을 1개씩만 부여하게 되면,
멀티프로세스 상황에서 메모리 낭비, Context Switch 비용 폭증 등의 문제가 생겼다.
다시 말해, 프로세스 당 실행 흐름을 하나만 주기애는 프로세스가 너무 무거웠다.

그래서 스레드라는 개념이 탄생하게 되었다.
스레드는 “주소 공간과 자원은 공유하고, 실행 흐름만 여러 개 두자”라는 개념이다.
따라서 스레드는 한 프로세스 내에서 여러 개가 존재할 수 있으며,
한 프로세스 내에 스레드가 여러 개 있는 것을 멀티스레드라고 한다.

멀티스레드 상태에서는 하나의 프로세스 안에서 여러 실행 흐름이 존재하기 때문에 같은 메모리와 커널 자원을 동시에 접근하게 된다.

이번엔 스레드의 특징을 살펴보자.

스레드는 기본적으로 프로세스 내부의 작은 실행 흐름이므로, 프로세스의

  • 메모리
  • 파일
  • 권한
  • 실행 흐름
  • 레지스터

을 공유한다.

다만, 스택은 공유되지 않는다.
이는 스택의 특징 때문인데,
스택은 프로세스의 실행 흐름이 물리적으로 기록되는 메모리 영역이기 때문이다.

따라서 스레드가 스택을 공유하게 될 경우,

스레드 A가 push를 하면 스레드 B의 리턴 주소를 덮거나,
스레드 B가 ret을 수행할 때 스레드 A의 스택 값을 리턴 주소로 인식할 수 있다.

이렇게 되면 실행 흐름이 섞여서 프로그램이 크래시가 나거나 하는 등의 문제가 생겨
스레드가 정상 동작할 수 없게 된다.
따라서 스레드는 저마다의 스택을 갖게 되며 이것을 스레드 스택이라고 부른다.

다시 스레드에 대한 특징으로 돌아오면,
이렇게 프로세스의 자원을 공유하여 실행하기 떄문에
스레드는 프로세스보다 상대적으로 매우 빠르다.

그렇다면 스레드는 유저 공간의 프로세스에서만 사용하는 것일까?
당연하게도 커널 또한 스레드를 사용하며, 유저 스레드와 커널 스레드로 구분한다.

유저 스레드와 커널 스레드의 차이점은,

  • 유저 스레드는 유저 공간의 라이브러리에서 관리하고,
  • 커널 스레드는 커널이 직접 스케쥴링(Scheduling)하는 실행 단위

라는 것이다.

Linux에서의 스레드는 커널 입장에서 모두 task_struct로 인식되며,
프로세스와 스레드의 차이는 메모리(mm_struct)를 공유하는가의 차이뿐이다.

따라서 커널 입장에선 프로세스와 스레드는 거의 같은 존재이다.