본문 바로가기
CS

프로세스와 스레드

by memeseo 2021. 10. 20.

비전공자 개발자로서 현업에서 일하면서 가장 부족하다고 느끼는 부분은 네트워크 지식과 컴퓨터 사이언스다. 고래서 오늘부터 틈틈이 컴퓨터 사이언스 지식을 쌓아볼까 한다. 첫 포스팅은 기술면접에서 자주 등장하는 프로세스(Process)와 스레드(Thread)다.

 

 

📌keypoint. '프로그램 > 프로세스 > 스레드'

프로세스와 스레드에 대해 자세히 알기 위해서는 '프로그램' 개념에 대해서 먼저 알아야 한다.

 

프로그램(Program)

: 파일이 저장 장치에 저장되어 있지만 메모리에는 올라가지 않은 정적인 상태.

 

모든 프로그램은 운영체제가 실행되기 위한 메모리 공간을 할당해줘야 실행될 수 있다.

고로 프로그램이란 아직 실행되지 않은 파일 그 자체를 가리키는 말이며 쉽게 말해 코드 덩어리이다.

 

프로세스(Process)

: 운영체제로부터 자원을 할당받은 작업의 단위.

 

실행 파일(프로그램)을 실행하게 되면, 실행하는 순간 해당 파일이 컴퓨터 메모리에 올라가게 되고 이렇게 동적인 상태가 된 프로그램을 프로세스라고 한다.

그러니까, 그냥 단순히 '실행되고 있는' 컴퓨터 '프로그램'이라고 생각하면 된다.

 

스레드(Thread)

: 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위.

 

과거에는 프로그램을 실행할 때 실행 시작부터 끝까지 프로세스 하나만 사용했지만 프로그램이 나날이 복잡해지면서 새로운 방법이 필요했다. 간단히 생각하면 다수의 프로세스를 통해 자원을 공유하는 방식을 떠올릴 수 있겠지만, 프로세스는 안전성을 위해 자신에게 할당된 메모리 내의 정보에만 접근할 수 있도록 제약을 두고 있어 이러한 발상의 실현은 불가능하다. (다른 프로세스에 접근하기 위한 방법으로 프로세스간 통신 > IPC, inter-process communication이 있긴 하지만 이건 현재 주제에는 벗어나니까 언급X) 이를 해결하기 위한 방법으로 프로세스를 여러개로 쪼개어 처리하는 작은 단위인 '스레드' 개념이 생겨났다.

 

프로세스가 진행되는 동안 스레드의 실행 과정 (By I, Cburnett, CC BY-SA 3.0)

이렇게 탄생한 스레드는 스레드끼리 프로세스의 자원을 공유하면서 프로세스 실행 흐름의 일부가 된다.

아까 프로그램이 코드 덩어리라고 했는데, 스레드도 코드에 비유하자면 코드 내에 선언된 함수들이 되고 따라서 main 함수 또한 일종의 스레드라고 할 수 있다. 즉, 스레드는 프로세스의 코드에 정의된 절차에 따라 실행되는 특정한 수행 경로이다.

 

🔎프로세스와 스레드의 작동 방식

위에 프로그램이 프로세스가 되기 위해서는 운영체제로부터 메모리를 할당 받아야 한다고 언급했다. 이때 운영체제는 프로세스마다 각각 독립된 메모리 영역(Code, Data, Stack, Heap)을 할당해준다.

 

(이미지 출처: Heee's Development Blog)

 

이때, 프로세스는 최소 1개의 스레드(메인 스레드)를 가지게 된다.

프로세스는 다른 프로세스의 변수나 자료 구조에 접근할 수 없으므로, 프로세스에게 부여된 스레드끼리 영역을 공유한다.

 

(이미지 출처: Heee's Development Blog)

그림을 통해 알 수 있듯이, 스레드는 프로세스 내에서 각각 Stack만 따로 할당 받고, Code, Data, Heap 영역을 공유한다. 이처럼 결합도 높은 방식은 한 스레드에서 오류가 발생하면 같은 프로세스 내의 다른 스레드가 모두 강제로 종료 될 수 있다는 것을 유추해볼 수 있다. 쉽게 말해 스레드를 코드(프로세스) 내에서 함수(스레드)로 생각해보면, 코드 내 어떤 함수 하나가 Segmentation Fault등의 오류가 발생하게 되면 해당 코드는 다른 함수 모두에 대한 작업을 중단하고 프로세스 실행을 끝내버린다는 것이다. 

 

🔎멀티 태스킹과 멀티 스레드

멀티 태스킹

: 하나의 운영체제 안에서 여러 프로세스가 실행되는 것.

 

위에 프로세스는 다른 프로세스와 자원을 공유할 수 없다고 언급한 게 무색할 만큼 대부분 한 프로그램을 실행하면서 다른 프로그램에 있는 정보를 가져온 경험을 해봤을 것이다.

 

*프로세스 간 정보를 공유하는 방법

1. IPC(Inter-Process Communication)
2. LPC(Local Inter-Process Communication)
3. 별도로 공유 메모리를 만들어 정보를 공유 함.

 

위와 같은 방법으로 프로세스끼리 자원을 공유할 수 있다. 하지만 이러한 방법은 Context-Switcing 과정에서 캐쉬 메모리 초기화 등 무거운 작업이 진행되고 오버헤드를 발생시킨다. 또한, 프로세스는 각각의 독립된 메모리 영역을 할당받기 때문에 프로세스 사이에서 공유하는 메모리가 없어 Context-Switching이 발생하면 캐쉬에 있는 모든 데이터들을 리셋하고 다시 캐쉬 정보를 불러와야 한다. 

 

*what Context-Switcing?

: CPU에서 여러 프로세스를 돌아가면서 작업을 처리하는데 이 과정은 Context-Switching이라고 한다. 구체적으로, 동작 중인 프로세스가 대기를 하면서 해당 프로세스의 상태(Context)를 보관하고, 대기하고 있던 다음 순서의 프로세스가 동작하면서 이전에 보관했던 프로세스의 상태를 복구하는 작업을 말한다.

 

정리하여 장단점을 비교해보자.

✔ 장점
1. 여러 개의 자식 프로세스 중 하나에 문제가 발생하면 그 자식 프로세스만 죽는 것 이상으로 다른 영향이 확산하지 않음.

✔ 단점
1. Context-Switching에서 오버헤드
2. 프로세스 사이의 어렵고 복잡한 통신 기법(IPC)

 

멀티 스레드

: 하나의 프로세스가 여러 작업을 여러 스레드를 사용하여 동시에 처리하는 것.

 

✔ 장점
1. Context-Switching할 때 공유하고 있는 메모리만큼 메모리 자원을 아낄 수 있다.
2. 스레드는프로세스 내의 Stack 영역을 제외한 모든 메모리를 공유하기 때문에 통신의 부담이 적어 응답 시간이 빠르다.

✔ 단점
1. 스레드 하나가 프로세스 내 자원을 망쳐버린다면 모든 프로세스가 종료될 수 있다.
2. 자원을 공유하기 때문에 필연적으로 동기화 문제가 발생할 수 있다.

 

멀티 태스킹과 멀티 스레드의 장단점을 각각 비교해보았을 때, 멀티 태스킹은 통신 기법도 복잡하고, 무겁고, 비효율적으로 보인다. 하지만 이와 마찬가지로 멀티 스레드 또한 단일 프로세스일 경우 멀티 스레드의 효과를 기대할 수 없고, 운영체제가 스케줄링을 자동으로 해주지 않기 때문에 프로그래머가 적절한 기법을 직접 구현해야 하므로 주의를 요하며 디버깅이 까다롭다는 단점을 가지고 있다. 즉, 각자의 상황에 맞춰 사용할 필요가 있다.

 

🔎결론

1. 프로세스는 다른 프로세스와 정보를 공유하려면 IPC를 사용하는 등 번거로운 과정을 거쳐야 하지만, 스레드는 기본 구조 자체가 메모리를 공유하는 구조이기 때문에 다른 스레드와 정보 공유가 쉽다.

2. 즉, '멀티태스킹'보다 '멀티스레드'가 자원을 아낄 수 있다.

3. 하지만 스레드 간의 자원 공유는 전역 변수를 이용하므로 동기화 문제에 신경 써야 한다.

4. 이 장황한 모든 문제는 결국 운영체제의 시스템 자원을 효율적으로 관리하기 위해서다.

 

🔎프로세스와 스레드, 왜 알아야 할까?

약간 이런 근본적인 질문을 해야 잘 외워지므로(?) 덧붙이자면 결국 운영체제가 작업을 실행할 때 자원을 할당하는 단위를 알고있는지, 프로그램을 멀티 스레드로 구현한다는 게 무엇인지, 멀티 스레드로 구현할 때 장,단점을 알고 있는지를 알 수 있어야 좋은 코드를 짤 수 있기때문이라고 답하겠다.

 

 

 

References

https://commons.wikimedia.org/w/index.php?curid=2233446 

https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

https://brunch.co.kr/@kd4/3

https://velog.io/@raejoonee/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4