Process
process : 실행 중인 program
address space
각 process는 현재 자신이 사용하는 memory를 표현하는 address space를 갖고 있다.
이 때 address space는 크게 다음 4구역으로 나뉜다.
- text section : program code를 저장하는 장소(정적)
- stack
- process 실행 중 발생되는 function call로 인한 parameters 값과 return address, local variables 등을 저장하는 장소(동적)
- process 간의 context switching이 발생할 때, 현재 cpu register 값을 stack에 저장하는 장소(동적)
- data section : static variables 또는 global variables를 저장하는 장소(정적)
- compile할 때부터 전체 크기를 알 수 있으므로 고정된 위치에 저장
- heap section
- 동적 메모리 할당을 위한 장소(동적)
💡 stack vs heap
stack : 위치와 순서에 따라 의미하는 값이 정해져 있고, 순차적으로 값에 접근
heap : 위치와 순서에 무의미하게 값이 정해지고, 랜덤하게 값에 접근

위의 address space의 최댓값은 OS의 표현 가능 bit로 결정된다.
address space에서의 주소는 실제 memory 주소가 아닌 process 마다 각자 갖고있는 가상의 주소이므로 logical address라고 불리고, 실제 cpu adress는 physical address라고 불린다.
process state
프로세스는 다음과 같은 상태를 갖는다.
- new : process가 막 생성된 상태 : cpu 할당 X / scheduling 대상 X
- ready : process가 cpu의 할당을 기다리는 상태 : cpu 할당 X / scheduling 대상 O
- running : process가 실행되고 있는 상태 : cpu 할당 O / scheduling 대상 X
- waiting : process가 특정 event가 발생하기를 기다리는 상태 : cpu 할당 X / scheduling 대상 X
- terminated : process가 모든 작업을 마친 상태 : cpu 할당 X / scheduling 대상 X

- running 중 process가 I/O 요청이나 다른 작업을 요청해 해당 결과물을 받아야 하는 경우에 waiting 상태에 들어가게 된다.
⇒ 이 때 I/O 요청을 대기하게 되는 경우는 이전 내용에서 봤던 것처럼 현재 진행 중인 I/O interrupt가 다음 I/O interrupt 발생 전까지 끝나지 않는 경우와 같을 때 발생한다. - multitasking을 위해 특정 시간이 지나면 timer가 cpu에게 interrupt를 보내게 된다. interrupt를 받은 cpu는 context switching을 하고 현재 작업 중인 process를 ready 상태로 보내게 된다.
PCB
OS에서는 process를 자료구조로 인식하여 작업을 처리한다.
이 때 OS가 process를 인식하는 자료구조를 PCB(Process Control Block)이라고 한다.
PCB에는 process의 현재 상태를 나타내는 다양한 정보가 저장되어 있다.
- Process state
- PC(program counter) : address space에서 stack 부분에 PC가 저장되어 있는 주소를 가리키는 pointer
- CPU registers : address space에서 stack 부분에 register가 저장되어 있는 주소를 가리키는 pointer
- CPU scheduling information : scheduling에서 해당 process가 어떤 우선순위인지에 대한 정보
- Memory-management information : process가 현재 memory에서 어느 위치에 할당되어 있는지
- accounting information : 지금까지 어떤 resource를 얼마나 할당받았는지에 대한 정보
- I/O status information
Context Switching

context switching 시 현재까지 진행된 register 정보를 각 process의 stack에 저장한 뒤,
다음에 실행될 process의 stack에 저장된 register 정보를 cpu register에 로드한다.
⇒ 위의 작업이 모두 memory operations이므로 속도가 매우 느리다. (overhead!!)
또한 context switching 후에는 사용하던 cache flushing한다.
⇒ 따라서 context switching가 일어난 후에는 cache miss가 연속적으로 발생한다. (overhead!!)
process scheduling queues
OS는 여러 종류의 queues를 관리해 각 목적에 맞춰 queue scheduling을 한다.
- Job queue : 현재 생성된 모든 process를 갖고있는 queue
- Ready queue : ready 상태의 process를 갖고있는 queue
- Device queue : I/O를 기다리는 process를 갖고있는 queue
⇒ 각 queue는 실제 process를 queue에 넣는 것이 아니라 PCB를 가리키는 pointer를 queue에 저장한다.

- fork 시 child가 실행이 종료할 때까지 기다리는 parent process인 경우 child가 끝난 후 ready queue로 들어간다.
⇒ fork : process가 다른 process를 생성을 요청하는 system call - 특정 evnet 후 interrupt를 기다리는 경우 interrupt signal을 받은 후 ready queue로 들어간다.
shedulers
OS에서 sheduler는 크게 3가지가 있다.
- Long-term scheduler(= job scheduler)
- new process → ready process로 만들어 주는 scheduler
- 해당 scheduler가 동시에 도는 process의 개수(multiprogramming degree)를 결정하게 된다.
- 빈번하게 불리지는 않으므로 빠를 필요는 없다.
- Medium-term scheduler
- memory가 부족할 때 memory에 올라와 있는 process 중 어떤 것을 제거할지를 결정하게 된다.
- Short-term scheduler(= CPU scheduler)
- ready process → running process로 만들어 주는 scheduler
- 매우 빈번하게 불리므로 scheduler가 빠르게 동작해야 한다.
- processes는 다음 두 가지 종류로 분류될 수 있다.
- I/O-bound process : I/O 작업을 주로 하는 process로 cpu를 자주 점유하지만 점유기간은 짧다.
- CPU-bound process : 계산 작업을 주로 하는 process로 cpu를 자주 점유하지는 않지만 점유기간이 길다.
Process Creation
- parent process가 child process를 생성하는 방식으로 process가 반복적으로 생성된다.
- 따라서 process의 구조가 tree 구조를 띄게 된다.
⇒ 최초의 process는 OS kernel이 생성해준다. 이 때 최초의 process를 init process라고 한다. - children의 반환값은 parent가 받아 처리한다.
- 이러한 parent와 children process의 경우 resource를 다음과 같이 설정할 수 있다.
- 모든 resource를 공유한다.
- children이 parent의 일부 resource만 공유 받는다.
- resource를 공유하지 않는다.
- 또한 children의 address space를 parents의 address space를 완전히 복사할 것인지를 설정할 수 있다.
⇒ address space를 완전히 복사한다는 것은 전체적인 program은 parent process와 동일하다는 것!
- UNIX에서는 fork() 후 exec()가 없으면 parent address space를 그대로 사용
- UNIX에서는 fork() 후 exec()가 있다면 children를 별도의 program으로 사용
- 위의 경우에서 결국 fork() 후에는 일시적으로 parent process와 완전히 동일한 children이 생성되게 된다.
⇒ (exec()이 실행되기 전이고, children의 PC 역시 fork() 다음 주소를 가리키고 있기 때문에) - 따라서 해당 시점에는 누가 parent이고 누가 children인지 알 수 없게 된다. 이러한 문제점을 해결하기 위해 OS에서는 fork() 명령어의 반환값을 child는 0을, parent는 child의 pid를 반환해준다.

Process Termination
process가 종료되는 경우는 2가지가 있다.
- exit
- process가 마지막 코드까지 실행을 끝냈을 때
- abort
- process 실행 중간에 종료되는 경우
parent가 children이 있는 경우에 abort된다면 OS에 따라 다음과 같이 동작한다.
- 모든 children도 같이 종료한다. : cascading termiation
- kernel이 해당 child process(orphan process)를 별도로 관리
Interprocess communication
기본적으로 각 process 간은 independent하기 때문에, 한 process가 다른 process에 접근하면 안된다.
하지만 두 process가 협력해 실행되어야 하는 경우(cooperating processes), 정보를 교환할 필요가 있다.
⇒ interprocess communication(IPC)
IPC
- shared memory : 두 process 간 공유 메모리를 사용
- message passing : message를 보내는 방식으로 정보 교환
IPC(interprocess communication) - Message parsing
send와 receive operations이 있다.
synchronization : message passing 방식이 다음 두 가지로 나뉜다.
- blocking(synchronous) : message를 보낸 뒤 응답을 받아야 다음 실행
- non-blocking(asynchronous) : message를 보낸 뒤 응답을 받지 않고 즉시 다음 실행
Threads

기존의 parent process의 address space를 그대로 복사해 child process를 만드는 과정을 거쳐 동일한 코드를 실행하는 여러 process를 만들 수 있었다.
하지만 이러한 방식은 parent의 모든 address space를 복사해야 하기 때문에 overhead가 크고, 메모리 공간 낭비도 심하다는 단점이 있었다.
따라서 multithread를 사용함으로써, 하나의 process에서 정적인 부분은 공유하고 동적인 부분만 분할해 하나의 프로세스 내부에서 여러 동작을 처리할 수 있도록 하였다.
- 공유되는 부분 : code section, data section, os resources(files, signals ...)
- 공유되지 않는 부분 : pc, register set, stack space
Hyperthreading
이러한 thread의 개념이 도입되면서 program이 실행되는 최소 단위가 process → thread가 되었다.
하지만 threads 간의 context switching도 가능해지면서 cpu scheduling을 할 대상도 늘어나게 되었고 그만큼 context switching overhead도 커지게 되었다.
이러한 문제점을 해결하고자 hyperthreading기법이 제시되었다.
hyperthreading이란 cpu의 register set을 한 개를 추가로 더 둬 다음 context switching될 상태값들을 미리 올려놓는 것이다.
이렇게 함으로써 context switching의 overhead를 없애고 즉시 다음 context로의 전환이 가능해졌다.
또한 hyperthreading으로 인해 context switching 간의 overhead가 완전히 사라짐으로써 두 작업이 거의 동시에 진행이 될 수 있게 되었다.
즉 예를 들어 2ghz cpu가 context switching overhead가 발생되지 않으므로 1ghz cpu 2개와 동일한 연산이 가능해지는 것이다.
⇒ I/O event 등으로 context switching이 발생할 때 cpu가 1개면 결국 overhead가 발생하지만, hyperthreading의 경우 기존에 overhead없이 발생하던 context switching을 안하고 하나의 process만 돌릴 수 있게 됨으로 하나의 process를 다시 2ghz로 돌릴 수 있게 된다.
Benefits
- Responsiveness
- 하나의 process를 여러 thread가 나눠 실행하거나 관리한다면, 하나의 thread가 waiting 상태에 들어가더라도 다른 thread가 작업을 계속할 수 있기 때문에 응답성이 향상된다.
- resource sharing
- 정적인 address space를 공유하기 때문에 메모리 효율이 높아진다.
- Economy
- child process를 만드는 것보다 하나의 thread를 만드는 것이 더 비용이 적다.
- scalability
- cpu가 여러개 있는 경우 하나의 process 내의 thread를 동시에 여러 cpu에 할당할 수 있게 된다.
user threads vs kernel threads
user threads : os가 threads 단위를 인식하지 못 하는 경우로 os는 process 단위로 block을 시키기 때문에 하나의 thread가 block되면 다른 thread도 같이 block되게 된다.
kernel threads : os가 threads 단위를 인식하는 경우로 os는 threads 단위로 block을 하게 된다.
threading issue
- thread가 process를 만드는 경우 만들어진 process도 thread를 만들어야 하는가?
- child process에 exec()이 있는 경우 thread를 만들지 않는다.
- child process에 exec()이 없는 경우에는 parent process와 동일한 thread 구성을 만든다.
- thread를 abort시킬 때 바로 종료를 시켜도 되는가?
⇒ thread 간은 전역 변수를 공유하고 있기 때문에 문제가 생길 수 있다.
- asynchronous cancellation : 즉시 해당 thread를 제거
- deffered cancellation : thread가 정말 종료돼도 되는지 주기적으로 체크하면서 thread가 사용한 resource를 정리할 수 있는 시간을 준다.
- process에게 특정 신호를 전달한 경우, 어떤 thread가 해당 신호를 받아야 하는가?
⇒ 여러가지 옵션이 있다.
- 모든 thread에게 전달
- 지정된 thread에게 전달
- 신호와 관련있을 것 같은 특정 thread에게 전달
- thread를 만드는 방식을 어떻게 할 것인가?
- 미리 빈 thread를 만들고 필요할 때 바로 채워서 사용
⇒ 응답시간은 줄지만 resource 사용률이 올라간다. - 요청받으면 그 때 생성
⇒ 응답시간이 늘지만 resource 사용률이 줄어든다.
- 미리 빈 thread를 만들고 필요할 때 바로 채워서 사용
- threads끼리 필요한 특정 데이터를 어떻게 정의할 것인가?
⇒ tid(thread id)와 같은 정보를 저장하고 이용할 수 있어야 한다.
multicore programming
multicore + multithread를 사용함으로써 하나의 process를 여러 thread로 쪼개 각 core에서 동시에 돌릴 수 있게 된다.
하지만 실제로 이렇게 동작하도록 설계된 program는 흔치 않다. 이러한 이유는 하나의 program을 논리적으로 여러 core에 나눠 실행할 수 있도록 설계해야 하기 때문이다.
- dividing activities : 적절한 양을 각 thread에 분리해야 한다.
- balance : 각 thread가 균형있게 동작해야 한다.
- data splitting : 각 thread가 적절한 데이터를 분배받아야 한다.
- data dependency : 분배받은 각 data 간의 dependency가 없도록 해야 한다.
- testing and debugging : 여러 코드가 동시에 상호작용하며 동작하기 때문에 test와 debug가 매우 어렵다.
참고
- Operating System Concepts
- 운영체제, 한양대학교 강수용 교수님
'CS > OS' 카테고리의 다른 글
| [Operating System] Process Synchronization 1 (0) | 2024.07.27 |
|---|---|
| [Operating System] CPU Scheduling (1) | 2024.07.27 |
| [Operating System] Operating System Overview (0) | 2024.07.27 |
| [Operating System] Computer System Overview (0) | 2024.07.27 |
| [Operation System] Course Overview (0) | 2024.07.27 |