main

프로세스와 스레드 I

Log
17

전공 지식 없이 컴퓨터의 프로그램을 이용하는데는 문제 없어 왔지만 소프트웨어를 개발하는 사람으로서 컴퓨터 실행 내부 요소를 따져보게 될때, 아마 컴퓨터 운영체제에 대해 입문하게 되면 가장 먼저 듣고 배우게 될 개념이 프로세스스레드입니다. 결론부터 말하자면 이 둘을 한마디로 정의하자면 다음과 같습니다.

프로세스와 스레드

  • 프로세스: 운영체제로부터 자원을 할당받은 작업의 단위
  • 스레드: 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위

일단 프로세스의 작업의 단위 라는 단어와 스레드의 실행 흐름의 단위 라는 단어를 기억하고 쉽게 이에 대해 포스팅해보겠습니다.


프로그램과 프로세스

프로그램 (Program)

프로그램은 윈도우의 *.exe 파일이나 Mac의 *.dmg 파일과 같은 컴퓨터에서 실행 할 수 있는 파일을 통칭합니다.
단, 아직 파일을 실행하지 않은 상태 이기 때문에 정적 프로그램(Static Program), 줄여서 프로그램(Program)이라고 부릅니다.

어떠한 프로그램을 개발하기 위해선 자바나 C언어와 같은 언어를 이용해 코드를 작성하여 완성됩니다. 즉, 프로그램은 쉽게 말해서 그냥 코드 덩어리라고 말할 수 있습니다.


프로세스 (Process)

프로그램이 그냥 코드 덩어리이면, 프로세스는 프로그램을 실행시켜 정적인 프로그램이 동적(動的)으로 변하여 프로그램이 돌아가고 있는 상태를 말합니다. 즉, 컴퓨터에서 작업 중인 프로그램을 의미하는 것입니다.

ctrl + alt + del 단축키를 눌러 우리가 항상 보던 '작업' 관리자를 열어보면 개념에 대해서 쉽게 이해할 수 있습니다.

231005-204806

모든 프로그램은 운영체제가 실행되기 위한 메모리 공간을 할당해 줘야 실행될 수 있습니다. 그래서 프로그램을 실행하는 순간 파일은 컴퓨터 메모리에 올라가게 되고, 운영체제로부터 시스템 자원(CPU)을 할당받아 프로그램 코드를 실행시켜 우리가 서비스를 이용할 수 있게 되는 것입니다.

프로그램과 프로세스는 어플리케이션을 실행 하냐 안하냐 차이일 뿐이라서 일반적으로 같은 개념으로 이야기할 때가 많지만, 정의를 보았듯이 엄밀히 따지면 이 둘은 다른 개념인 것입니다.

최종적으로 이 둘을 간단 명료하게 정리하면 아래와 같습니다.


  • 프로그램
    • 어떤 작업을 하기 위해 실행할 수 있는 파일
    • 파일이 저장 장치에 있지만 메모리에 올라가 있지는 않은 상태
    • 쉽게 말해 코드 덩어리
  • 프로세스
    • 실행되어 작업중인 컴퓨터 프로그램
    • 메모리에 적재되고 CPU 자원을 할당받아 프로그램이 실행되고 있는 상태
    • 코드 덩어리를 실행한 것

스레드

스레드 등장배경

과거에는 프로그램을 실행할 때 프로세스 하나만을 사용해서 이용했었습니다. 하지만 기술이 발전됨에 따라 프로그램이 복잡해지고 다채로워짐으로써 프로세스 작업 하나만을 사용해서 프로그램을 실행하기에는 한계가 있었습니다.

오늘날 컴퓨터는 파일을 다운 받으며 다른 일을 하는 멀티 작업은 너무 당연한 기능이라고 생각할지 모르겠지만, 과거에는 파일을 다운받으면 실행 시작부터 실행 끝까지 프로세스 하나만을 사용하기 때문에 다운이 완료될때까지 하루종일 기다려야 했습니다. 그렇다고 동일한 프로그램을 여러 개의 프로세스로 만들게 되면, 그만큼 메모리를 차지하고 CPU에서 할당받는 자원이 중복되게 될 것입니다. 스레드(Thread)는 이러한 프로세스 특성의 한계를 해결하기 위해 탄생하였습니다.


스레드의 개념

스레드란, 하나의 프로세스 내에서 동시에 진행되는 작업 갈래, 흐름의 단위 를 말합니다.

이해하기 쉽게 비유를 들자면, 크롬 브라우저가 실행 되면 프로세스 하나가 생성될 것입니다. 그런데 우리는 브라우저에서 파일을 다운 받으며 온라인 쇼핑을 하면서 게임을 하기도 합니다.

231005-205612

즉, 하나의 프로세스 안에서 여러가지 작업들 흐름이 동시에 진행되기 때문에 가능한 것인데, 이러한 일련의 작업 흐름들을 스레드라고 하며 여러개가 있다면 이를 멀티(다중)스레드 라고 부릅니다.

아래 그림에서 보듯이 하나의 프로세스 안에 여러개의 스레드들이 들어 있다고 보면 됩니다. 스레드 수가 많을 수록 당연히 프로그램 속도도 동시에 하는 작업이 많아져 성능이 올라가게 됩니다.

231005-205913

일반적으로 하나의 프로그램은 하나 이상의 프로세스를 가지고 있고, 하나의 프로세스는 반드시 하나 이상의 스레드를 갖게 됩니다. 즉, 프로세스를 생성하면 기본적으로 하나의 main 스레드가 생성되게 됩니다. 스레드 2개, 3개.. 는 프로그램을 개발한 개발자가 직접 프로그래밍하여 위치 시켜주어야 합니다.


프로세스와 스레드의 메모리

프로세스 자원 구조

프로그램이 실행되어 프로세스가 만들어진다면 다음 4가지의 메모리 영역으로 구성되어 할당받게 됩니다.
231005-210400

  • 코드 영역(Code / Text) : 프로그래머가 작성한 프로그램 함수들의 코드가 CPU가 해석 가능한 기계어 형태로 저장되어 있습니다.
  • 데이터 영역(Data) : 코드가 실행되면서 사용하는 전역 변수나 각종 데이터들이 모여있다. 데이터영역은 .data ,.rodata, .bss 영역으로 세분화 됩니다.
    • .data : 전역 변수 또는 static 변수 등 프로그램이 사용하는 데이터를 저장
    • .BSS : 초기값 없는 전역 변수, static 변수가 저장
    • .rodata : const같은 상수 키워드 선언 된 변수나 문자열 상수가 저장
  • 스택 영역(Stack) : 지역 변수와 같은 호출한 함수가 종료되면 되돌아올 임시적인 자료를 저장하는 독립적인 공간입니다. Stack은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다. 만일 stack 영역을 초과하면 stack overflow 에러가 발생합니다.
  • 힙 영역(Heap) : 생성자, 인스턴스와 같은 동적으로 할당되는 데이터들을 위해 존재하는 공간입니다. 사용자에 의해 메모리 공간이 동적으로 할당되고 해제됩니다.

코드 영역과 데이터 영역은 선언할 때 그 크기가 결정되는 정적 영역이지만, 스택 영역과 힙 영역은 프로세스가 실행되는 동안 크기가 늘어났다 줄어들기도 하는 동적 영역입니다.

예를 들어 프로그램이 여러개 실행된다면 메모리에 프로세스들이 담길 주소 공간이 생성되게 되고 그 안에 Code, Data, Stack, Heap 공간이 만들어지게 됩니다.

1. 크롬을 실행한다. -> 프로세스가 생성됨 (안에 Code, Data, Stack, Heap 생성)
2. 카카오톡을 실행한다. -> 프로세스가 생성됨 (안에 Code, Data, Stack, Heap 생성)
3. 엑셀을 실행한다. -> 프로세스가 생성됨 (안에 Code, Data, Stack, Heap 생성)
4. 디스코드를 실행한다. -> 프로세스가 생성됨 (안에 Code, Data, Stack, Heap 생성)

즉, 위의 예시를 기반으로 한다면 총 4개의 프로세스가 생성될 것입니다.


스레드의 자원 공유

스레드는 프로세스가 할당 받은 자원을 이용하는 실행의 단위로서, 스레드가 여러개 있으면 우리가 파일을 다운 받으며 동시에 웹 서핑을 할 수 있게 해줍니다. 스레드끼리 프로세스의 자원을 공유하면서 프로세스 실행 흐름의 일부가 되기 때문에 동시 작업이 가능한 것입니다. 그래서 아래 사진과 같이 하나의 프로세스 내에 여러개의 스레드가 들어있는 상태인 것입니다.

231005-211231

이때 프로세스의 4가지 메모리 영역(Code, Data, Heap, Stack) 중 스레드는 Stack만 할당받아 복사하고 Code, Data, Heap은 프로세스내의 다른 스레드들과 공유된다. 따라서 각각의 스레드는 별도의 stack을 가지고 있지만 heap 메모리는 고유하기 때문에 서로 다른 스레드에서 가져와 읽고 쓸 수 있게 됩니다.

231006-115747

stack은 함수 호출 시 전달되는 인자, 되돌아갈 주소값, 함수 내에서 선언하는 변수 등을 저장하는 메모리 공간이기 때문에, 독립적인 스택을 가졌다는 것은 독립적인 함수 호출이 가능하다 라는 의미입니다. 그리고 독립적인 함수 호출이 가능하다는 것은 독립적인 실행 흐름이 추가된다는 말입니다.
즉, stack을 가짐으로써 스레드는 독립적인 실행 흐름을 가질 수 있게 되는 것입니다.

반면에 프로세스는 기본적으로 프로세스 끼리 다른 프로세스의 메모리에 직접 접근할 수는 없습니다.

이렇게 구성한 이유는 하나의 프로세스를 다수의 실행 단위인 스레드로 구분하여 자원을 공유하고, 자원의 생성과 관리의 중복성을 최소화하여 수행 능력을 올리기 위해서입니다.


프로세스의 자원공유

기본적으로 각 프로세스는 메모리에 별도의 주소 공간에서 실행되기 때문에, 한 프로세스는 다른 프로세스의 변수나 자료구조에 접근할 수는 없습니다. 그렇다면 프로세스는 영원히 다른 프로세스 정보에 접근할 수 없을까요?

현재 우리가 사용하는 대부분의 컴퓨터 프로그램을 보면 다른 프로그램에 있는 정보를 가져오는 경우를 사실 종종 볼 수 있습니다. 이처럼 특별한 방법을 통해 프로세스가 다른 프로세스의 정보에 접근하는 것이 가능합니다. 프로세스 간 정보를 공유하는 방법에는 다음과 같은 방법들이 있습니다.

  • IPC(Inter-Process Communication) 사용
  • LPC(Local inter-Process Communication) 사용
  • 별도로 공유 메모리를 만들어서 정보를 주고받도록 설정

위와 같은 방법들이 있지만, 프로세스 자원 공유는 단순히 CPU 레지스터 교체뿐만이 아니라 RAM과 CPU 사이의 캐시 메모리까지 초기화되기 때문에 자원 부담이 크다는 단점이 있습니다. 그래서 다중 작업이 필요한경우 스레드를 이용하는 것이 훨씬 효율적이라, 현대 컴퓨터의 운영체제에선 다중 프로세싱을 지원하고 있지만 다중 스레딩을 기본으로 하고 있습니다.


포스팅이 길어져서 다음 편으로 나눠 포스팅하겠습니다.
다음은 멀티프로세스와 멀티스레드의 원리와 차이점에 대해 이야기해볼까합니다.

Reference Doc

[운영체제] 프로세스와 스레드
👩‍💻 완전히 정복하는 프로세스 vs 스레드 개념


김다은 이모지
Daeun Kim
Junior Frontend Engineer