Effective Java - Thread & Process
Updated:
OS
Thread & Process 정리
Process와 Thread의 개념
Program
Program과 Process의 차이 부터 알자.
Program은 실행파일. 즉, 실행 되기를 기다리는 파일 시스템에 존재하는 실행파일이 프로그램입니다.
운영체제가 프로그램에게 독립적인 메모리 공간을 할당해주지 않았고, 정적인 상태로 가만히 있는 코드를 말합니다.
Process
-
동적인 개념으로는 실행된 프로그램을 의미
프로그램인 실행파일의 명령어와 정적 데이터가 메모리에 적재되고, CPU를 차지하여 그 프로그램을 실행시키게 되는 것을 의미
또한, 메모리에 올라와 실행되고 있는 프로그램의 인스턴스라고 부르기도 한다.
따라서 하나의 프로그램을 실행하는 인스턴스는 여러개가 될 수 있다. - 프로세스가 생성 될 때마다 OS로 부터 시스템의 자원을 할당 받는다.
- CPU 시간
- 운영되기 위해 필요한 주소 공간
- Code, Data, Stack, Heap의 구조로 되어 있는 독립된 메모리 영역
각 프로세스는 별도의 주소 공간에서 실행되며, 한 프로세스는 다른 프로세스의 변수나 자료구조에 접근할 수 없다.
한 프로세스가 다른 프로세스의 자원에 접근하려면 프로세스 간의 통신(IPC, inter-process communication)을 사용해야 한다.
- Process Control Block(PCB)
운영체제가 프로세스 실행을 제어하기 위해서는 프로세스의 정보를 알아야 합니다.
프로세스 제어 블록(PCB)은 운영체제가 프로세스 스케줄링을 위해 프로세스에 관한 모든 정보를 가지고 있는 데이터베이스이다.
각 프로세스가 생성될 때마다 고유의 PCB가 생성되고, 프로세스가 완료되면 PCB는 제거됩니다.
프로세스는 CPU를 점유하여 작업을 처리하다가 상태가 전이되면, CPU가 처리하던 작업의 내용들을 자신의 PCB에 저장하고, 다음에 다시 CPU를 점유하여 작업을 수행해야 할 때 PCB로부터 해당 정보들을 CPU에 넘겨와서 계속해서 하던 작업을 진행할 수 있게 됩니다. 즉, 프로세스 상태 관리와 문맥교환(Context Switching)을 위해 필요한 것입니다.
PCB에는 프로세스 식별자(Process ID) ,프로세스 상태(Process State), CPU 스케줄링 정보, 메모리 관리 정보, 프로세스에 할당된 자원들을 가리키는 포인터 등의 프로세스의 관한 정보가 들어있습니다.
과거에는 프로그램을 실행할 때 실행 시작부터 실행 끝까지 프로세스 하나만을 사용해서 진행했다고 한다.
하지만 시간이 흐를수록 프로그램이 복잡해지고 프로세스 하나만을 사용해서 프로그램을 실행하기는 벅차게 되었다.
따라서, 프로세스와는 다른 더 작은 실행 단위 개념이 필요하게 되었고, 이 개념이 바로 스레드입니다.
Thread
스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체를 의미하며, 프로세스가 할당받은 자원을 이용하는 실행의 단위라고 생각하면 된다.
스레드는 한 프로세스 내에서 동작되는 여러 실행의 흐름으로, 프로세스 내의 주소 공간이나 자원을 스레드끼리 공유하면서 실행합닌다.
따라서, 스레드는 프로세스 내에서 각각 Stack만 따로 할당받고 Code, Data, Heap 영역은 공유한다.
한 스레드가 프로세스 자원을 변경하면, 다른 이웃 스레드도 그 변경 결과를 즉시 볼 수 있다.
기본적으로 하나의 프로세스가 생성되면 하나의 스레드가 같이 생성되며, 이를 메인 스레드라고 부르며, 스레드를 추가로 생성하지 않는 한 모든 프로그램 코드는 메인 스레드에서 실행됩니다.
모든 프로세스에는 한 개 이상의 메인 스레드가 존재하여 작업을 수행합니다
프로세스는 단순한 껍데기일 뿐, 실제 작업은 스레드가 담당합니다.
프로세스 생성 시 하나의 주 스레드가 생성되어 대부분의 작업을 처리하고 주 스레드가 종료되면 프로세스도 종료됩니다.
멀티 프로세스 & 멀티 스레드
멀티 프로세스
하나의 응용프로그램을 여러 개의 프로세스로 구성하여 각 프로세스가 하나의 작업을 처리하도록 하는 것을 의미합니다.
여러개의 프로세스를 만들기 위해, 프로세스는 부모프로세스(parent process)라는 상위계층과 자식프로세스(child process)라는 하위계층으로 존재하게 됩니다.
하나의 부모프로세스는 여러 개의 자식프로세스를 관리하는데, 여러 개의 자식프로세스가 하나의 CPU에서 동시에 처리되는 것처럼 보이는 것을 멀티태스킹(multitasking)이라고 합니다.
앞서 말했듯이, Process는 각자 고유의 메모리 영역을 얻으므로, 부모-자식 관계라고 해도 자신만의 메모리 영역을 가지게 됩니다.
만일, 하나의 컴퓨터에 여러 CPU 장착하게 되면 하나 이상의 프로세스들을 동시에 처리할 수 있으므로, 효율적이게 됩니다.
멀티 프로세스 방식은 각 프로세스가 독립된 구조기 때문에 안정성이 높다는 장점이 있지만, Context Switching
으로 인한 성능 저하라는 큰 문제가 있습니다.
Context Switching CPU에서 여러 프로세스를 돌아가면서 작업을 처리하는 데 이 과정을 Context Switching라 한다.
구체적으로, 동작 중인 프로세스가 대기를 하면서 해당 프로세스의 상태(Context)를 보관하고, 대기하고 있던 다음 순서의 프로세스가 동작하면서 이전에 보관했던 프로세스의 상태를 복구하는 작업을 말한다.
프로세스는 각각의 독립된 메모리 영역을 할당받았기 때문에 프로세스 사이에서 공유하는 메모리가 없어,
Context Switching가 발생하면 캐쉬에 있는 모든 데이터를 리셋하고 다시 캐쉬 정보를 불러와야 합니다.
따라서 멀티 프로세스는 Context Switching 과정에서 캐쉬 메모리 초기화 등 무거운 작업이 진행되고 많은 시간이 소모되는 등의 오버헤드가 발생하게 된다.
마지막으로 프로세스는 프로세스들 사이의 변수를 공유할 수 없으므로, 통신을 위하여 IPC라는 복잡한 기법을 사용하게 됩니다.
멀티 스레드
하나의 응용프로그램을 여러 개의 스레드로 구성하고 각 스레드로 하여금 하나의 작업을 처리하도록 하는 것
따라서, 자원의 효율성과 처리 비용 감소 및 응답시간 단축을 위해 멀티 스레드를 사용
스레드는 메모리를 서로 공유할 수 있다고 언급했습니다. 따라서 컨텍스트 스위칭(Context Switching) 시에 공유 메모리 만큼의 자원 손실이 줄어들게 됩니다.
프로세스를 생성하여 자원을 할당하는 시스템 콜이 줄어들어 시스템 자원을 효율적으로 관리할 수 있다.
마지막으로 힙 메모리를 공유하기 때문에, IPC와 같이 복잡한 프로세스 통신 없이 효율적인 일처리가 가능하게 됩니다.
하지만 멀티 스레드 방식에도 단점이 존재하는데, 프로세스는 독립된 공간을 가지므로 프로세스를 실행하다가 오류가 발생해서 강제로 종료하더라도 서로 공유하지 않는다면 영향을 주지 않습니다.
그런데 스레드의 경우는 다릅니다.
스레드는 Code/Data/Heap 메모리 영역의 내용을 공유하기 때문에 어떤 스레드 하나에서 오류가 발생한다면 같은 프로세스 내의 다른 스레드 모두가 강제로 종료되버립니다.
원을 공유하기 때문에 필연적으로 동기화 문제가 발생할 수 있습니다.
따라서 주의 깊은 설계가 필요하고 디버깅이 까다롭게 됩니다.
결론
프로세스는 Program을 메모리에 적재시키고 cpu를 사용하는 운영체제로부터 시스템 자원을 할당받는 작업의 단위
스레드는 프로세스 내에서 실행되는 흐름의 단위
운영체제가 프로세스에게 Code/Data/Stack/Heap 메모리 영역을 할당해 주고 최소 작업 단위로 삼는 반면, 스레드는 프로세스 내에서 Stack 메모리 영역을 제외한 다른 메모리 영역을 같은 프로세스 내 다른 스레드와 공유한다.
프로세스는 다른 프로세스와 정보를 공유하려면 IPC를 사용하는 등의 번거로운 과정을 거쳐야 하지만, 스레드는 기본 구조 자체가 메모리를 공유하는 구조이기 때문에 다른 스레드와 정보 공유가 쉽다. 때문에 멀티태스킹보다 멀티스레드가 자원을 아낄 수 있게 된다. 다만 스레드의 스케줄링은 운영체제가 처리하지 않기 때문에 프로그래머가 직접 동기화 문제에 대응할 수 있어야 한다.
출처
Joshua Bloch. Effective Java 3/E. n.p.: 인사이트, 2018년 11월 1일.