스레드(thread)는 실행의 단위이다. 조금 더 정확하게 표현하자면, 스레드란 프로세스를 구성하는 실행의 흐름 단위이다. 그리고 하나의 프로세스는 여러 개의 스레드를 가질 수 있다. 스레드를 이용하면 하나의 프로세스에서 여러 부분을 동시에 실행할 수 있다.
개발자로서 일을 하게 된다면 반드시 스레드를 다루게 될 날이 올 것이다. 하지만 스레드와 관련한 내용은 프로그래밍 기본서만 학습하면 놓치기 쉬운 부분이기도 하다. 이번 강의를 통해 스레드와 멀티 스레드란 무엇인지, 그리고 멀티 스레드는 멀티프로세스와 어떤 차이가 있는지를 학습해보자.
전통적인 관점에서 보면 하나의 프로세스는 한 번에 하나의 일만을 처리했다. 앞선 절에서도 한 번에 하나의 작업을 처리하는 프로세스를 상정했다. 가령 웹 브라우저, 게임, 워드 프로세서 프로세스가 있을 때 이 모든 프로세스가 하나의 실행 흐름을 가지고 한 번에 하나의 부분만 실행되는 프로세스를 가정했다. ‘실행의 흐름 단위가 하나’라는 점에서 이렇게 실행되는 프로세스들은 단일 스레드 프로세스라고 볼 수 있다.
하지만 스레드라는 개념이 도입되면서 하나의 프로세스가 한 번에 여러 일을 동시에 처리할 수 있게 되었다. 즉, 프로세스를 구성하는 여러 명령어를 동시에 실행할 수 있게 된 것이다.
이런 점에서 볼 때 스레드는 ‘프로세스를 구성하는 실행 단위’라고 볼 수 있다. 이 말이 조금 추상적으로 들릴 수도 있겠지만, 스레드의 구성 요소를 파악하면 조금 더 분명히 와닿을 것이다. 스레드는 프로세스 내에서 각기 다른 스레드 ID, 프로그램 카운터 값을 비롯한 레지스터 값, 스택으로 구성된다. 각자 프로그램 카운터 값을 비롯한 레지스터 값, 스택을 가지고 있기에 스레드마다 각기 다른 코드를 실행할 수 있다.
여기서 중요한 점은 프로세스의 스레드들은 실행에 필요한 최소한의 정보 (프로그램 카운터를 포함한 레지스터, 스택)만을 유지한 채 자원을 공유한다는 것이 스레드의 핵심이다. 위 그림의 예를 보면 스레드 1만의 코드/데이터/힙 영역이 있고, 스레드 2만의 코드/데이터/힙 영역이 있는게 아니라는 의미이다.
정리하면, 프로세스가 실행되는 프로그램이라면 스레드는 프로세스를 구성하는 실행의 흐름 단위이다. 실제로 최근 많은 운영체제는 CPU에 처리할 작업을 전달할 때 프로세스가 아닌 스레드 단위로 전달한다. 그리고 스레드는 프로세스 자원을 공유한 채 실행에 필요한 최소한의 정보만으로 실행된다.
<aside> 🗒️ 리눅스 운영체제에서 프로세스 vs 스레드
많은 운영체제가 프로세스와 스레드를 구분하지만, 프로세스와 스레드 간에 명확한 구분을 짓지 않는 운영체제도 있다. 대표적으로 리눅스가 그러하다. 리눅스는 프로세스와 스레드 모두 실행의 문맥(context of execution)이라는 점에서 동등하다고 간주하고 이 둘을 크게 구분짓지 않는다. 프로세스와 스레드라는 말 대신 테스크(task)라는 이름으로 통일하여 명명한다.
</aside>
하나의 프로세스에 여러 스레드가 있을 수 있다는 말을 조금 더 자세히 알아보자. 컴퓨터는 실행 과정에서 여러 프로세스가 동시에 실행될 수 있고, 그 프로세스를 이루는 스레드는 여러 개 있을 수 있다고 했다. 이때 여러 프로세스를 동시에 실행하는 것을 멀티프로세스(multiprocess), 그리고 여러 스레드로 프로세스를 동시에 실행하는 것을 멀티스레드(multithread)라고 한다.
여기서 한 가지 궁금증이 생긴다. 동일한 작업을 수행하는 단일 스레드 프로세스 여러 개를 실행하는 것과 하나의 프로세스를 여러 스레드로 실행하는 것은 무엇이 다를까?
예를 들어 “hello, os”를 화면에 출력하는 간단한 프로그램이 있다고 해보자. 이 프로그램을 세 번 fork하여 실행하면 화면에는 “hello, os”가 세 번 출력된다. 이 프로그램 내에 “hello, os”를 출력하는 스레드를 세 개 만들어 실행해도 화면에는 “hello, os”가 세 번 출력된다. 이 둘은 무엇이 다를까? “hello, os”가 세 번 출력된다는 결과는 같은데 말이다.