개요
학부 강의를 듣거나 프로젝트를 수행하며 Process, Thread라는 단어를 들을 기회는 정말 많을 것입니다.
개발자 필수 지식이기도 하고, 이들에 대한 이론적인 지식을 배워왔을 것이기도 합니다.
간단히 말해서, Process는 프로그램이 실행되는 단위, Thread는 작업 실행 단위입니다.
우리가 java로 프로그램을 만들어 실행한다면 그것은 Process로 동작할 것입니다.
해당 프로그램의 main메서드에서 구구단을 계산하는 함수를 실행한다면, 이것은 Thread로 동작할 것입니다.
개발을 하며 Process와 Thread 둘 중 하나를 이용해 다중 작업을 진행해야 한다면, Thread를 선택하는 것이 좋은 경우가 많습니다.
Process가 필요로 하는 자원보다 Thread가 필요로 하는 자원이 훨씬 적기 때문입니다.
이번 글에서는 Process와 Thred의 주요 차이점을 보고, 왜 Thread가 세상에 나타났는지 이해해보도록 하겠습니다.
Process, PCB(Process Control Block)
PCB의 경우 Process의 정보를 저장하는 자료구조입니다.
PID, PC, 레지스터, 메모리 정보, Accounting information, i/o정보 등 수많은 정보들을 포함합니다.
Process를 실행하다 다른 Process를 실행하는 순간이 올 것입니다.
이러한 경우 Context Switching이 발생합니다.
두 Process P1, P2가 있다고 할 때,
1. P1 실행중
2. OS Interrupt or System Call로 인하여 OS에서 P1의 PCB를 저장
3. P2의 PCB를 load
4. P2를 실행
5. OS Interrupt or System Call로 P2의 PCB를 저장
6. P1을 다시 실행
...
이러한 순서의 반복으로 OS는 Process의 Context Switching을 진행합니다.
그런데, Process는 기본적으로 실행 중 다른 Process로 정보를 읽어서는 안 되는 친구입니다.
따라서 여러 Process가 있다 하더라도 Process들의 정보를 서로 알 수 없습니다.
(프로세스 간 통신 방법 - IPC)
그래서 CPU의 레지스터와 캐시에 다른 PCB가 올라갈 때 재사용할 수 있는 정보가 없습니다.
그렇다면, Process만을 사용할 때 발생하는 문제를 알 수 있습니다.
1. PCB가 이미 큰 자료구조이다.(포함하고 있는 자료구조가 크고, 이를 저장하고 로드하는 데 자원소모)
2. CPU에 올릴 때 Locality를 이용할 수 없다.(캐시가 있든 말든 전부 메모리에서 로드하고 저장해야 한다.)
3. Process간 정보를 공유할 수도 없다.
4. System Call, Interrupt가 발생하면 Kernel단에 갔다 와야 하는 문제가 생긴다.
Thread, TCB(Thread Control Block)
TCB는 이러한 문제점을 근본적으로 해결할 수는 없지만, 자원 소모를 극적으로 낮출 수 있습니다.
PCB는 해당 Process내에 Thread들을 저장하기 위해 자체적인 공간을 가지고 있습니다.
TCB의 경우 Process내의 PCB에 포함되어 있는 것을 볼 수 있습니다.
특히 주목할 점은, TCB는 PCB보다 저장하는 정보도 적을 뿐더러 공유하는 자원이 있다는 부분입니다.
한 프로세스 내에 존재하는 Thread는 Heap, Static, Code를 공유합니다.
따라서 Process 사이의 통신 방법인 IPC를 사용하지 않아도 됩니다.
또, Thread간의 Context Switching이 발생함에 있어 Stack만 교체해도 된다는 이점을 가지고 있습니다.
1. TCB는 PCB보다 작은 자료구조이다.
2. CPU에 올릴 때 Locality를 이용할 수 있다.(공유자원이 존재한다.)
3. Thread간 공유 자원이 있어 정보 교환을 할 수 있다.
다만, Kernel단에 갔다 와야 한다는 점은 동일합니다.
LifeCycle
Process와 Thread는 LifeCycle에서도 조금씩 다른 점이 있습니다.
Process
new : 프로세스가 생성된 상태입니다. OS Kernel에 존재하는 Ready Queue에 Process 적재시 Ready Status가 됩니다.
ready : 프로세스가 CPU로부터 메모리 할당을 기다리는 상태입니다. Process Scheduler에 의해 Process가 할당되면 running상태로 변합니다. 이것을 dispatch라 합니다.
running : Process가 동작하는 상태입니다. interrupt발생시 ready상태로, 실행이 끝나면 exit, i/o등 event발생시 waiting상태로 전환됩니다.
waiting : i/o, event가 완료되면 ready상태로 돌아갑니다.
새 프로세스가 실행된다면, 이러한 과정을 거칠 것입니다.
1. 프로그램이 실행된다. new상태로 OS Ready Queue에 올라가고, ready status로 전환된다.
이때, Ready Queue는 Linked List형태로 구현되며 각 PCB는 다음 PCB를 가리키는 포인터 필드를 가진다.
2. 메모리 공간을 할당받기를 기다린다.
3. Scheduler에 의해 메모리 공간을 할당받고, running상태가 된다.
Process가 진행되며 불려온 명령어들은 Fetch, Decode, Operand, Execute과정을 거치며 실행된다.
4. 프린터 출력, 마우스 입력, 키보드 입력 등의 IO, event발생시 해당 Process는 Waiting상태가 된다. IO, event가 종료되면 다시 ready상태로 돌아간다.
5. 2~4상태를 반복하다 Process종료시 terminated상태로 돌아간다.
Thread
new : 새 스레드 객체가 생성된 상태입니다.
runnable : start메서드가 실행되어, thread가 언제나 JVM위에서 실행될 준비가 된 상태가 된 것을 뜻합니다.
running : 스레드가 실행되는 상태입니다.
waiting : 다른 스레드가 통지할 때까지 기다리는 상태입니다.
timed_waiting : 주어진 시간동안 대기하는 상태입니다.
blocked : 스레드가 동기화 코드 영역에 들어갔을 때, 해당 스레드 작업이 끝날 때까지 같은 자원에 접근하는 스레드들에 락이 걸린 상태입니다. 외부통신, IO등으로 인해 발생합니다.
새 스레드가 실행된다면, 이러한 과정을 거칠 것입니다.
1. 새 스레드 객체가 생성된다.
2. start()메서드로 JVM이 스레드를 만들고, runnable상태로 만든다.
3. runnable, running상태를 반복ㄱ하며 스레드가 실행된다.
4. 해당 스레드가 공유객체, syncronized resource에 접근하는 경우 같은 자원에 접근하는 다른 스레드는 blocked상태가 된다.
5. 이후 이 스레드가 공유객체에 대한 용무를 마치면, Scheduler에 의해 다른 스레드가 순차적으로 blocked상태를 풀고 작업을 진행한다.
6. wait(), join()메서드를 사용하는 경우 waiting상태로 들어간다. notify()메서드 호출시 다시 동작한다.
7. sleep()메서드를 사용하는 경우, timed_waiting상태로 들어간다.
8. 3~7을 반복하고, 작업 종료시 terminated단계가 되어 스택에서 지워진다.
Process는 다른 Process의 자원에 접근하기 위해 특별한 방법을 사용해야 하지만, Thread는 기본적으로 공유하는 자원이 있기 때문에 blocked라는 상태가 존재합니다. 또, Thread는 sleep()메서드로 기다리는 상태가 될 수 있어 timed_wait상태 또한 존재합니다.
이렇게 Process, Thread의 차이점들을 살펴보았습니다.
'JAVA > Thread' 카테고리의 다른 글
[Thread] 5. Virtual Thread 알아보기 - 3 (0) | 2024.02.04 |
---|---|
[Thread] 4. Virtual Thread 알아보기 - 2 (0) | 2024.01.28 |
[Thread] 3. Virtual Thread알아보기 (0) | 2023.12.19 |
[Thread] 2. JAVA에서 Thread사용하기 (1) | 2023.12.19 |