프로세스와 스레드 간단 비교
프로세스와 스레드를 비교하기 전에 프로그램이 무엇인지에 대해서 알아야 한다.
프로그램은 .exe 파일과 같이 컴퓨터에서 실행할 수 있는 파일을 통칭한다.
이런 프로그램을 만들기 위해서는 C나 Java와 같은 언어로 코드를 작성하여 완성한다. 즉, 프로그램은 코드 덩어리이다.
프로세스 (Process) | 스레드 (Thread) |
운영체제로부터 자원을 할당받은 작업의 단위 | 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위 |
프로세스는 쉽게 말해서 컴퓨터에서 하나의 프로그램이 실행되면 하나의 프로세스가 할당된다.
과거에는 프로그램이 실행하면 시작부터 끝까지 하나의 프로세스만을 사용하여 프로그램을 구동시켰다.
하지만, 프로그램의 크기가 커지고 복잡해질수록 프로세스 하나만으로 프로그램을 구동시키기 어려워졌다.
그렇다면 한 프로그램을 여러 프로세스에 할당하면 해결될까?
아니다. 운영체제는 안정성을 위해 프로세스마다 자신에게 할당된 메모리 영역만 접근하도록 제약을 두고 있다.
그래서 프로세스보다 작은 실행 개념 단위가 필요했고 그 때 등장한 것이 스레드다.
프로세스 (Process)
프로그램이 코드 덩어리 즉 정적 프로그램이라면, 프로세스는 프로그램을 실행 시켜 동적인 프로그램, 작업 중인 프로그램을 의미하는 것이다.
OS는 프로그램을 실행하면서 디스크에 저장된 데이터를 메모리 영역으로 로드한다.
프로세스는 OS로부터 독립된 메모리 영역 (코드, 데이터, 스택, 힙)을 할당받으며, 다른 프로세스의 영역은 접근할 수 없다.
•
프로세스의 메모리 영역 구조 (높은 주소에서 낮은 주소 값 순)
1.
스택 영역 (Stack Area) : 지역 변수, 함수의 파라미터, 반환되는 주소 값 등이 저장되는 영역이다.
높은 주소 값에서 낮은 주소 값으로 메모리가 할당되며, 영역 크기는 컴파일 때 결정된다.
2.
힙 영역 (Heap Area) : 사용자에 의해 동적으로 메모리 할당이 일어나는 영역이다.
낮은 주소 값에서 높은 주소 값 순으로 메모리가 할당되며 영역 크기는 런타임 때 결정된다.
3.
데이터 영역 (Data Area) : 전역 변수, 정적 변수, 배열, 구조체 등이 저장되는 영역이다.
자세히 보면 BSS(Block Stated Symbol)영역과 데이터 영역으로 다시 나뉘는데
BSS 영역은 초기화 되지 않은 변수를 데이터 영역은 초기화 한 변수를 저장한다.
4.
코드 영역 (Code Area) : 실행할 코드가 기계어로 컴파일되어 저장되는 영역으로 텍스트 영역이라고도 불린다.
스택 영역과 힙 영역은 동적으로 메모리 할당이 가능해 두 영역 사이에 빈 메모리 공간이 존재한다.
스택 영역은 LIFO방식, 높은 주소 값에서 낮은 주소 값 순으로 사용하고 힙 영역은 FIFO방식으로 낮은 주소 값에서 높은 주소 값으로 사용한다.
스택영역과 힙 영역의 화살표는 두 영역이 런타임에 동적으로 크기가 변경되는 동적 영역이기때문에 이를 표현한 것이다.
스택 영역이 힙 영역을 침범하는 경우를 스택 오버플로(Stack Overflow), 힙 영역이 스택 영역을 침범하는 것을 힙 오버플로(Heap Overflow)라고 한다.
•
프로그램과 프로세스
프로세스 (Process) | 프로그램(Program) |
실행되어 작업중인 프로그램 | 실행할 수 있는 파일 |
메모리에 적재되어 CPU 자원을 할당받아 프로그램이 실행되고 있는 상태 | 파일이 저장 장치에 있지만 메모리에는 올라가 있지는 않은
정적인 상태 |
코드 덩어리를 실행한 것 | 코드 덩어리 |
•
프로세스 메모리 구조 그림
* PCB (Process Control Block)
OS는 프로세스를 제어하기 위해 프로세스의 정보를 저장하는데 이를 PCB라 한다.
PCB는 프로세스의 현재 상태, 프로세스의 고유 ID인 PID, 부모 프로세스의 PID, 자식 프로세스의 PID, 다음 실행할 명령어의 주소, 프로세스의 우선 순위, 메모리 제한 등을 저장한다.
프로세스의 상태도
모든 프로세스는 CPU에 의해 생성되고 소멸되는 과정을 거친다.
프로세스는 생성(new), 준비(ready), 대기(waiting), 실행(running), 종료(terminated) 5가지 상태를 가진다.
•
생성(new) : 프로세스가 PCB를 가지고는 있지만 OS로부터 승인 받기 전
•
준비(ready) : OS로부터 승인받은 후 준비 큐에서 CPU할당을 기다림
•
실행(running) : 프로세스가 CPU를 할당받아 실행함
•
대기(waiting) : 프로세스가 입출력이나 이벤트를 기다려야 해서 CPU 사용을 멈추고 기다림
•
종료(terminated) : 프로세스가 종료됨
스레드 (Thread)
스레드란 하나의 프로세스 내에서 동시에 진행되는 작업 흐름의 단위를 말한다.
프로세스는 한 개 이상의 스레드를 가지고 있고 스레드는 프로세스 안에 존재하므로 스레드는 프로세스의 메모리 공간을 이용한다.
스레드는 프로세스로부터 지역 변수를 저장하는 스택 영역을 할당받고, 전역 변수를 저장하는 나머지 힙, 데이터, 코드 영역은 다른 스레드와 공유한다.
따라서 각각의 스레드는 별도의 스택 영역을 가지고 있지만 힙 메모리는 서로 읽고 쓸 수 있다.
그렇기 때문에 서로 참조하지 않는 프로세스는 오류가 발생해도 다른 프로세스에 영향을 주지 않지만, 한 프로세스 내의 한 스레드가 오류가 발생한다면 프로세스 내의 모든 스레드는 종료하게 된다.
멀티 프로세스 & 멀티 스레드
멀티 프로세스와 멀티 스레드 개념을 알기전에 동시성과 병렬성을 짚고 넘어가야 한다.
•
동시성(Concurrency) : 하나의 코어에서 여러 작업을 번갈아 가면서 처리하는 방식이다. CPU는 한 번에 하나의 작업만 처리할 수 있어서 여러 작업을 조금씩 돌아가면서 처리한다.
하나의 CPU에서 여러 작업을 번갈아 가면서 처리하기 위해 처리 중인 작업을 교체하는 것을 콘텍스트 스위칭이라고 한다.
동시성은 하나의 시스템이 여러 작업을 동시에 처리하는 것처럼 보이게 하는 것이다.
•
병렬성(Parallelism) : CPU가 여러 개(멀티 코어) 있어서 각 CPU에서 각 작업을 동시에 처리하는 방식이다.
멀티 프로세스
멀티 프로세스는 응용 프로그램 하나를 여러 프로세스로 구성하는 것을 의미한다.
멀티 프로세스 환경에서는 한 프로세스가 죽어도 다른 프로세스의 영향을 주지 않는다. (프로세스는 서로 독립적인 메모리 영역을 가지고 있기 때문에…)
추가적으로 각 프로세스는 독립된 실행 흐름을 가지고 있으며, 자신만의 CPU 자원을 할당받아 실행되기 떄문에 다른 프로세스의 장애와 상관없이 정상적으로 동작할 수 있다.
멀티 프로세스는 위에서 보았듯이 안정적으로 프로그램을 실행할 수 있다는 장점이 있지만 그만큼 프로세스를 여러 개 사용하기 때문에 메모리와 자원이 많이 든다는 단점이 있다.
CPU는 한번에 하나의 작업(한 프로세스)만 처리할 수 있다.
따라서 멀티 프로세스 환경에서 CPU가 여러 프로세스를 처리할려면 처리 중인 프로세스를 교체하는 콘텍스트 스위칭 작업이 이뤄져야 한다.
이 과정에서 CPU는 기존에 처리하던 프로세스가 할당받은 메모리 영역을 다른 프로세스가 사용할 수 있게 교체하면서 시간과 메모리가 필요한데 이를 오버헤드(overhead)라 한다.
프로세스는 CPU에게 독립적인 메모리 공간을 할당받기 때문에 프로세스 간에 공유할 메모리가 있다면 IPC(Inter Process Communication)를 통해 프로세스 간에 자원을 공유해야 한다.
이는 공유할 메모리는 직접 참조하는 것보다 효율적이다.
프로세스 간 통신 (IPC)
IPC는 OS가 관리하며 프로세스 간 데이터를 주고 받을 수 있는 안전한 채널을 제공한다.
한 프로세스가 장애가 발생해도 IPC를 통해 통신하는 다른 프로세스에는 영향을 주지 않는다.
컨텍스트 스위칭 (Context Switching)
CPU에서 실행 중이던 프로세스/스레드가 다른 프로세스/스레드로 교체되는 것을 말한다.
여기서 컨텍스트는 CPU에서의 프로세스/스레드의 상태를 의미한다.
즉, CPU가 실행 중인 프로세스나 스레드의 상태를 저장하고, 다른 프로세스나 스레드의 상태를 복원하여 실행을 전환하는 과정을 의미한다.
•
컨텍스트 스위칭이 발생하는 상황
◦
주어진 Time Slice를 다 사용했을 경우 운영체제가 다른 프로세스를 실행할 때
◦
입출력 작업이 필요할 때, CPU는 해당 프로세스의 I/O작업이 완료되기를 기다리지 않고 다른 작업을 처리함.
◦
우선 순위가 높은 프로세스가 대기 중일 때 낮은 우선순위의 프로세스를 중단시키고 실행
•
컨텍스트 스위칭 과정
1.
현재 실행 중인 프로세스의 상태를 저장한다.
2.
운영체제는 다음에 실행할 프로세스를 선택하고, 그 프로세스의 저장된 상태를 복원한다.
3.
CPU는 해당 스레드를 복원된 상태부터 시작한다.
4.
위 과정을 계속 반복한다.
위 과정에서 이전 프로세스/스레드의 상태를 저장하고 이후 실행할 프로세스/스레드의 상태를 복원하는동안 CPU는 아무 일을 하지 못하는 상태가 된다.
이를 오버헤드(overhead)라 한다.
컨텍스트 스위칭은 쉽게 알 수 있듯이 많이 발생하면 당연히 좋지 않다.
컨텍스트 스위칭의 비용을 차지하는 작업들은 프로세스/스레드 상태 저장 및 복원, 캐시 미스가 발생했을 때가 있다.
* * 멀티 프로세스 환경에서의 컨텍스트 스위칭 vs 멀티 스레드 환경에서의 컨텍스트 스위칭
멀티 프로세스에서의 컨텍스트 스위칭 비용은 멀티 스레드 환경에서의 컨텍스트 스위칭 비용보다 높다.
즉, 스레드를 변경하는 것보다 프로세스를 변경하는 것이 더 큰 작업이다.
•
프로세스 간 컨텍스트 스위칭
메모리 간 오버헤드 발생 : 프로세스는 독립적인 메모리 공간을 사용하므로 전환 시 새로운 프로세스의 메모리 페이지를 설정하고
캐시를 무효화 하는 작업이 필요하다. 이 과정에서 캐시 미스 (오버헤드)가 발생할 수 있다.
메모리 맵핑, 캐시 미스, 시스템 자원 상태 복원 등이 필요하여 높은 비용과 더 많은 시간이 소요된다.
•
스레드 간 컨텍스트 스위칭
스레드는 같은 프로세스 내의 메모리 공간을 공유하기 때문에 메모리 매핑이나 페이지 테이블을 변경할 필요가 없다.
이로 인해 캐시 미스나 메모리 재설정같은 작업이 필요하지 않기 때문에 오버헤드의 비용이 적다.
•
프로세스/스레드 간 컨텍스트 스위칭 비교 표
구분 | 프로세스 간 컨텍스트 스위칭 | 스레드 간 컨텍스트 스위칭 |
메모리 관리 | 독립적인 가상 메모리 공간을
사용하므로 메모리 맵 변경 필요 | 같은 메모리 공간을 공유하기 때문에
메모리 맵 변경 없음 |
자원 관리 | 각 프로세스는 독립적인 자원을 관리하므로 자원 상태 저장 필요 | 자원을 공유하므로 자원 상태 저장 불필요 |
캐시 관리 | 새로운 프로세스 전환 시 캐시 미스 발생 가능 | 같은 프로세스 내이므로 캐시 미스 없음 |
전환 속도 | 전환 속도가 상대적으로 느림 | 전환 속도가 상대적으로 빠름 |
오버헤드 | 메모리 맵핑, 캐시 미스 등으로 높은 오버헤드 | 메모리 맵핑 변경이 필요없으므로 낮은 오버헤드 |
•
컨텍스트 스위칭 알고리즘
◦
Round-Robin 스케줄링 : 프로세스들에게 동일한 시간을 할당하고 순환하는 방식으로 타임 슬라이스마다 컨텍스트 스위칭이 발생한다.
◦
우선순위 기반 스케줄링 : 우선순위가 높은 프로세스가 실행되며, 우선순위가 바뀔 때만 컨텍스트 스위칭이 발생한다.
오버헤드 (overhead)
컨텍스트 스위칭에서 이전 스레드의 상태를 저장하고 이후 실행할 스레드의 상태를 복원하는 과정을 오버헤드라 한다.
이 뿐만 아니라 메모리를 관리하거나 동기화를 하는 과정에서도 발생한다.
오버헤드는 크게 시간 오버헤드와 공간 오버헤드로 나눌 수 있다.
시간 오버헤드는 추가적인 작업이나 연산으로 인해 더 많은 시간이 소요되는 현상이고, 공간 오버헤드는 추가적인 메모리나 저장 공간을 사용하는 현상이다.
컨텍스트 스위칭은 시간 오버헤드에 속한다.
멀티 스레드
멀티 스레드는 스레드를 여러 개 생성해 스레드들이 각자 다른 작업을 처리하는 것을 말한다.
스레드는 스레드 간에 힙, 데이터, 코드 영역을 공유하고 각 스레드마다 고유의 스택 영역을 가지고 있다.
따라서 스레드 간 자원 공유는 프로세스 간의 자원 공유보다 비용이 적고 빠르다.
멀티 프로세스 환경에서 발생하는 IPC를 사용하지 않고도 자원을 공유할 수 있기 때문에 시스템의 자원 소모가 적다.
컨텍스트 스위칭에서도 스레드 간에 공유하는 자원을 제외한 스레드 정보(Stack, Register)만 교체하면 되기 때문에 비용이 상대적으로 적다.
하지만 스택 영역을 다른 스레드와 함께 사용하므로 공유 자원에 대한 동기화가 필요하다.
멀티 스레드 환경에서는 여러 개의 스레드가 동시에 동작하기 때문에 각 스레드의 동작을 추적하기 어려워 디버깅이 어렵다.
또한 한 스레드에서 장애가 발생하면 같은 프로세스 내 다른 스레드에 영향을 미칠 수 있다는 단점이 존재한다.
스레드 간 동기화 문제를 해결하기 위해 임계영역에 대해 뮤텍스, 세마포어 방식을 활용하기도 한다.