4. 프로세스와 스레드의 차이
이 글은 다음의 강의를 수강하여 정리 및 복습하는 글임을 밝힙니다.
http://kocw.or.kr/home/cview.do?mty=p&kemId=1223639&ar=relateCourse
프로세스
프로세스란 연속적으로 실행되고 있는 컴퓨터 프로그램을 의미한다 (코드의 조각)
1. 프로세스는 자신만의 스택을 가진다.
2. 프로세스는 자신만의 메모리를 가진다.
3. 프로세스는 자신만의 파일입출력 테이블
4. 프로세스는 고유의 아이디를 가진다 (PID)
프로세스를 생성하는 것은 fork()라는 system call에 의해서 부모의 프로세스에서 새로운 자식 프로세스를 만드는 것으로 생성된다. 자식 프로세스는 부모 프로세스를 복사한다는 느낌으로 이해하겠습니다.
그래서 fork()함수에서 성공적으로 자식프로세스를 생성하는 경우 부모 프로세스는 자식 클래스의 PID를 return 받게되고, 자식 프로세스는 0을 return 받습니다.
만약 충분한 메모리를 가지지 않았거나, 프로세스가 너무 많은 경우로인해 fork() system call 함수가 실패하는 경우 새로운 프로세스는 만들어지지 않으며 -1이 return 됩니다.
좀비 프로세스
프로세스는 부모가 있어야 생성됩니다. 자식 프로세스는 종료될 때, SIGCHLD는 부모가 자식의 자원을 수거하고 반납하게 합니다. 그러나 자원을 반납하지 못한체 프로세스가 죽어버리는 경우가 있습니다. 이 경우를 좀비 프로세스라고 합니다.
고아(Orphan) 프로세스
이번에는 자식프로세스가 생성된 후 부모 프로세스가 죽어버리는 경우 자식 프로세스는 고아 프로세스가 됩니다. 이 때는 process 1 (최초의 프로세스)가 자식 프로세스를 입양하게 됩니다. 이를 통해 고아 프로세스가 좀비 프로세스가 되지 않도록 조치합니다.
자식 프로세스가 죽을 때 부모 프로세스가 현재 바쁘면, 자식 프로세스가 죽으면 안됩니다. 그렇기에 부모 프로세스는 자식 프로세스에게 좀 이따가 죽으라고 명령을 내립니다.(?) 그 때 내리는 system call이 wait() 입니다.
프로세스의 상태 변이
프로세스의 상태로는 New, Ready, Running Waiting, Terminated가 있습니다.
New 상태는 부모로 부터 자식 프로세스가 만들어지는 즉 프로세스가 생성되는 상태를 의미합니다. 이렇게 생성되면 Admitted(등록)을 거쳐 Ready (실행 가능한) 상태가 됩니다.
이제 실행 가능한 상태가 되었습니다. 운영체제는 CPU의 스케줄을 관리하고 있습니다. 이러한 스케줄에 따라 프로세스는 Running (CPU에 의해 처리되는) 상태로 넘어갑니다. 프로세스가 모두 처리되면 Terminated 상태가 되어 프로세스가 처리됩니다.
그러나 Running 중인 프로세스가 다시 Ready로 돌아가는 경우가 있습니다. 첫 번째는 interrupt입니다. CPU에 interrupt가 발생하면 현재 처리하고 있는 일을 잠시 멈추고 interrupt를 처리해야합니다. 그렇기 때문에 현재 Running 중인 프로세스는 잠시 동작을 멈추고 Ready 상태로 돌아갑니다.
두 번째는 I/O를 사용하는 경우입니다. 키보드에 입력을 기다린다거나 하드디스크에 store과정을 진행 중이라거나, 이 때 새로운 I/O가 처리될 때까지 CPU는 기다릴 수 없습니다. 이를 처리하기 위해서 프로세스는 Waiting 상태가 됩니다. 그리고 이를 처리하는 경우 Ready가 상태가 됩니다. 물론 I/O가 아니더라도 잠시 Waiting하라는 신호를 줄 수도 있습니다. 이 경우에도 프로세스는 Waiting 상태에 들어가게 됩니다. (강의에서 Waiting 상태로 들어가는 원인으로 1. disk access request , 2. inter-process messages, 3. a child process to finish)
Process Control Block (PCB)
프로세스 내부에서 프로세스를 관리하는 친구로 다음의 모습을 가집니다. (프로세스의 현재 상태를 지속적으로 업데이트합니다.)
그래서 각 프로세스들은 각각 PCB를 가지며 각각의 PCB에는 아래에 후술할 내용을 가지고 있습니다.
1. 프로세스의 ID
2. 부모 프로세스의 ID (PID)
3. 다음 프로세스의 주소값 (Linked List 형태)
4. 프로세스의 상태
5. List of thread control blocks (TCBs) : 프로세스 내부에는 스레드가 들어간다.
6. CPU의 정보 (레지스터 혹은 프로그램카운터(PC : CPU에게 다음 처리할 일을 알려주는 친구)
7. Memory-management information
8. Additional information
Context Switching
하나의 CPU와 하나의 레지스터를 가지고 있다고 가정을 하겠습니다. 프로세스 A와 B가 있는 상태에서 하나의 CPU를 사용하기 위해서 어떤식으로 이뤄지게 될까? 만약 프로세스 A와 프로세스 B가 동시에 실행되는 것처럼 보일려면 어떻게 해야할까?
프로세스 A가 실행되다가 잠시 이를 중단하고, 프로세스 B가 실행되도록하자 이를 Context Switching 이라고 합니다.
그림을 통해 확인해보면 먼저 프로세스 A가 CPU를 통해 작동을 하고 있습니다. 그러던 중에 interrupt 혹은 System call이 발생하면 Process B가 실행이되어야 합니다. 이 과정을 Context switching이라고 했습니다.
Context switching 과정동안 Process A는 실행을 멈추고 자신의 상태를 PCB A에 저장을 합니다. 그러면 Process B의 PCB B의 정보를 바탕으로 Process B가 CPU에서 실행됩니다. 이와 반대도 마찬가지입니다.
그러나 문제가 무엇일까? 우선 위의 과정은 Context switching을 SW적으로 구현한 모습입니다. 여튼 Context switching이 일어나는 동안 CPU는 무엇을 하고 있을까요
빨간색 화살표로 표시된 시간동안 CPU는 놀고 있습니다. 우리는 이를 오버헤드라고 부릅니다. 이 오버헤드를 줄이는게 목표가 되겠죠..
Process와 Thread의 차이
각 프로세스는 독립된 자원을 가지고 있습니다. 예를 들자면 독립된 메모리 영역(Address spaces)을 가지고 있습니다. Thread 같은 경우에는 프로세스의 내부에도 돌아가는데, 프로세스의 자원을 공유합니다. 그리고 Thread는 프로세스 내부에서 여러개가 돌아갈 수 있습니다.
그래서 프로세스는 독립된 자원을 가지고 있다하여, Protection이라고 하며, Thread는 여러 개의 thread가 돌아간다(Multi-threading)이라 하여 concurrency(동시성(병렬처리)라고 합니다.
다시 정리하자면 프로세스는 Thread와 Address Space로 구성되어 있습니다.
Thread는 Concurrency, 여러 개의 thread가 프로세스 내부에서 돌아간다
프로세스는 Protection, 독립된 주소 공간을 통해서 다른 프로세스와 분리된다(isolate)
Process는 다음으로 구성되어 있습니다.
1. 실행가능한 Code
2. Address space
3. Memory allocation
4. Stack
5. I/O state
6. CPU state
Multiple Processes
여러개의 프로세스가 돌아가는 상황에서 CPU는 하나의 코어 그리고 하나의 레지스터set을 가지고 있다고 가정을 해보겠습니다.
그러면 OS의 CPU scheduler에 의해 context switching이 일어나며 프로세스 A, B ... 의 실행을 돌아가면서 처리할 것입니다.
이 과정에서의 문제점은 context switching 과정에서의 큰 오버헤드(CPU가 논다)입니다.
Multiple Threads
하나의 프로세스가 2개의 Thread를 가진다고 가정을 해보겠습니다.
thread는 다음처럼 stack과 CPUstate는 가지지만 Memory와 I/O state는 프로세스의 자원이기 때문에 Thread들 끼리는 공유를 하게 됩니다.
그래서 여러개의 프로세스를 처리하는 과정과 동일합니다. thread는 cpu state에 자신의 현상태를 store 혹은 load하면서 context switching을 하며 일을 처리합니다.
그래서 thread간의 context switching의 장점이라고 한다면, cpu state만으로 context swtiching을 구현하기 때문에 적은 오버헤드가 될 수 있습니다.
만약 두 개의 코어를 가진 CPU라면 2개의 레지스터 set을 가지게 되며, 2개의 thread가 동시에 처리될 수 있습니다.
Hyper-Threading 기술은 cpu 코어가 2개의 레지스터 set을 가지며 context switching 동안 (스레드가 자신의 상태를 store, load 하는 동안) 오버헤드가 발생하지 않습니다.
Thread Control Block (TCB)
프로세스도 PCB를 가지는 것과 마찬가지로 thread도 TCB 를 가집니다. thread는 Memory, I/O state를 공유합니다. TCB는 다음으로 구성되어 있습니다.
1. Thread ID
2. PCB의 주소를 가리키는 포인터
3. 다음 thread 주소를 가리키는 포인터 (Linked List)
4. Thread의 상태
5. CPU information
6. Stack Pointer
7. Thread priority
Thread도 프로세스와 마찬가지로 다음과 같은 상태를 가집니다. 그래서 정리하자면 thread는 memory와 I/O state는 프로세스의 자원을 공유하고, 고유의 TCB, CPU state, stack을 가진다.