[OS] 4. Process Management
- IT/OS
- 2020. 12. 24.
1. 프로세스 생성
-
부모 프로세스가 자식 프로세스를 만듬. 사람처럼 아버지, 어머니 한 쌍의 부모가 아니라 부모 프로세스는 하나가 자식을 복제해서 만듬.
-
프로세스의 족보는 트리 형태 ⇒ 자식을 여러개 나을수(복제) 있음
-
프로세스가 실행이 되려면 자원이 있어야함(CPU, 메모리 등). 이 자원은 OS로부터 받음. 이 자원을 부모와 공유하는 경우가 있고 공유하지 않는 경우가 있음.
-
원칙적으로는 공유 X (공유하지 않는 것이 일반적) ⇒ 부모 프로세스가 자녀 프로세스를 복제하면 그때부터는 별도의 프로세스이기 때문에 서로 CPU, 메모리를 더 많이 얻으려고 경쟁하는 사이가 됨.
-
그럼 공유는 어떤 경우에? ⇒ 자식 프로세스는 부모 프로세스를 메모리에 그대로(코드, 데이터, 스택의 주소공간) 카피. 그러면 메모리에 결국 두 카피가 들어감. 메모리 낭비. 똑같은 내용을 만들 거면 당장 카피를 할 필요는 없을 것. 그래서 리눅스나 일부 모델에서는 모든 것을 다 카피하는 것이 아니라 공유할 수 있는 것은 일단 공유. 부모 프로세스를 카피해서 주소 공간이 만들어지는 것이 원칙이지만 몇 OS에서는 효율성을 위해 일단 카피하지는 않고 자식이 부모의 주소공간을 공유. Program counter만 하나 카피해서 똑같은 위치를 가리키도록. 그런 상태로 실행을 하다가 부모와 자식간의 내용이 달라지는 시점이 되면 그제서야 부모의 메모리 공간 일부를 카피해서 자식이 갖게됨. 그런 기법을 Copy-on-write (COW) 이라고 부름. write가 발생했을 때(내용이 바뀔 때), 그 때 copy를 하겠다는 말.
-
프로세스가 실행이 될 때 부모, 자식이 공존하면서 실행이 되는 경우가 있고 자식을 하나 생성한 다음에 그 자식이 종료될 때까지 부모가 기다리는(blocked 상태로) 경우가 있음.
-
부모가 자식 프로세스를 어떻게 생성을 할까? ⇒ 자식 프로세스가 부모의 주소 공간(코드, 데이터, 스택 등)을, CPU 문맥, Program counter 복사. OS에 있는 데이터들(PCB, 자원들)을 똑같이 복사. 이렇게 복제 생성이 되면 PC안에 있는 모든 복제 프로세스들은 다 같은 일만 해야할 것. 그러나 자식은 그 복제된 공간에 새로운 프로그램을 덮어 씌울수 있음. 보통은 프로세스의 생성이 이렇게 2단계를 거침. 복제 → 덮어씌우기. 과제를 할 때, 매번 같은 템플릿을 새로 만드는 것이 아니라 이미 만들어져있는 템플릿을 가져와 제목 바꾸고, 교수 이름 바꾸고 하는 것과 같음.
-
유닉스의 경우 복제는 fork() 라는 시스템 콜의 역할. 복제 생성을 한 다음 다른 프로그램으로 덮어 씌우는 것이 exec() 이라는 시스템 콜. 운영체제를 통해.
-
프로세스의 생성(부모 프로세스의 복제) ⇒ fork()
-
새로운 프로그램을 덮어 씌움 ⇒ exec()
-
이 fork() 와 exec()은 독립적이기 때문에 하나만 사용하는 경우도 있음. 프로세스만 생성하고 새로운 프로그램을 덮어 씌우지 않는 경우, exec()만 사용하여 자신을 그냥 새로운 프로그램으로 만드는 경우.
2. 프로세스 종료
-
보통 프로세스를 종료할 때 exit이라는 시스템 콜을 하면 프로세스가 종료됨. C언어를 예로 들면, main함수 안에 어떤 코드를 작성한 후 그냥 괄호만 닫아줘도 프로그램이 종료 되는데 그것은 컴파일러가 괄호를 닫는 지점에서 exit이라는 시스템 콜을 자동으로 넣어주기 때문.
-
현실 세계와는 다르게 프로세스의 경우는 항상 자식이 먼저 수행이 종료되어야 함. 이렇게 exit이 될 때는 자식이 부모에게 어떤 데이터를 보냄(wait 시스템 콜을 통해).
-
자발적으로 프로세스가 종료될 때는 exit 시스템 콜을 해주면 되고 비자발적으로 프로세스가 종료되는 경우가 있는데 부모에 의한 강제 종료.(about)
⇒ 자식을 낳아놨더니 너무 펑펑쓰는경우(자원을)
⇒ 일 시키려고 낳아놨더니 더이상 자식에게 시킬일이 없음
⇒ 부모 프로세스가 종료되는 경우. 자식이 먼저 종료된 다음에 부모가 종료되어야 하는데 부모가 종료되려고 하면 그 이전에 부모가 낳아놓은 모든 자식을 다 종료해야 함.
3. fork() 시스템 콜
-
위의 예는 C언어 코드. fork()라는 시스템 콜을 호출하고 있음. (OS에게 새로운 프로세스를 만들어 달라는 요청)
-
부모 프로세스가 자식 프로세스를 생성하면 자식 프로세스는 main 함수의 시작 부분부터 실행을 하는 것이 아니라 fork를 실행한 그 이후 시점부터 실행. fork를 통한 복제 생성은 부모 프로세스의 문맥을 그대로 복사. 따라서 Program counter가 가리키는 곳까지 복제. 부모에서 fork라는 것을 실행을 했고, fork가 끝나는 시점의 문맥에 이르렀으면 자식도 그대로 fork가 수행이 끝난 부분부터 다음 코드를 실행.
-
문제점 ⇒ fork()를 통해 생성된 자식이 정체성 혼란이와 자신이 부모, 부모를 자식이라고 주장하고 한다면? 또는 fork()하면 부모와 똑같은 것이 만들어지니까 모든 프로세스가 같은 제어흐름, 같은 역할을 할 수도 있음.
-
이러한 문제점을 막기 위해 fork()라는 시스템 콜을 할 때에는 OS가 자식과 부모를 구분할 수 있또록 fork()함수의 return 값을 다르게 줌. 부모 프로세스는 fork() 결과 값으로 양수가 얻어지고, 자식은 0을 가짐.
-
만약 위와 같이 프로세스가 계속 만들어진다면 비록 어느 순간(fork()시점)에서 부터는 다른 브랜치로 갈라질 수 있겠지만 그 위부분까진 같은 제어흐름. 그래서 존재하는 것이 exec() 시스템 콜
4. exec() 시스템 콜
-
exec() 시스템 콜은 어떤 프로그램을 완전히 새로운 프로세스로 태어나게 하는 역할.
-
위의 코드를 보면 execlp라는 함수가 있음. 이 함수가 exec() 시스템 콜을 함.
-
main 안의 코드가 실행이 되다가 exec()을 만나면 위의 기억들은 다 잊어버리고 새로운 프로그램으로 덮어씌어짐.
-
exec이라는 것이 꼭 자식을 만들어야만 해야하는 것이 아님. 위 그림에서 fork를 빼버리더라도(자식을 만들지 않더라도) exec을 사용할 수 있음. (밑 그림 참조)
-
이와 같은 코드의 경우 마지막 printf는 절대 실행 될 수 없음. 중간에 다른 프로그램으로 바뀌기 때문
5. wait() 시스템 콜
-
wait() 시스템 콜은 프로세스를 block 상태로 보내 잠들게 하는 것. 보통 block이라는 것은 오래된 event를 기다리고 그 event가 완료가 되면 다시 cpu를 얻을수 있는 상태(ready로 돌아가서).
-
자식 process가 종료될 때까지 부모 block상태. 자식이 종료되면 다시 ready.
-
코드를 보면 fork()의 결과 값을 통해 부모인지, 자식인지 판단한 후, 부모일 경우 wait() 시스템 콜 호출.
6. exit() 시스템 콜
-
프로세스를 종료시킬 때 호출하는 시스템 콜.
7. 프로세스와 관련된 시스템 콜
8. 프로세스 간 협력
프로세스는 보통 독립적. 이 독립적인 프로세스들 간에도 정보를 주고 받을 수 있도록 협력 메커니즘이 존재. 그것을 IPC라고 부름. 크게 두가지 방법. message passing, shared memory.
9. Message Passing
-
프로세스는 원치적으로 공유 변수 등을 두지 않아 다른 프로세스의 코드를 바꿀수 없음. 정보를 전달할 때 메세지를 보냄. 그것조차 직접 보낼 수 없고 운영체제 커널을 통해 전달.
-
Message Passing은 두가지 방법. 상대. 즉, 메세지를 받을 프로세스(수신자)의 이름을 명시하느냐 하지 않느냐에 따라 Direct Communication(직접 통신)과 Indirect Communication(간접 통신)으로 나뉨. 이렇게 두가지로 나뉘지만 어쨌든 커널을 통해 메세지를 전달하는 것은 똑같음. 다만 인터페이스 측면에서 직접 통신은 메세지를 전달하는 프로세스가 메세지 내용과 수신자를 명시(위 그림에서 Send(Q, message) ⇒ 나는 Q에게 message를 전달하겠다. 직접 전달 되는 것은 아님!! 커널을 통해.
-
간접 통신은 송신자 측에서 수신자를 명시하는 것이 아니라 우체통에다가 메세지를 집어 넣음. 경우에 따라 수신자가 여러 대상이 될 수도 있음.
Shared Meory 확인
-
위 그림은 메모리의 그림. Shared Memory 기법을 보면 'shared memory'라고 프로세스 A와 프로세스 B가 공유하는 메모리 영역이 존재.
-
프로세스 A, B는 각각 코드, 데이터, 스택 주소공간이 따로 있음. 그것을 물리적인 메모리에 맵핑할 때, 일부를 공유되도록 하는 것. 그러면 프로세스 A가 그 공유 영역에 어떤 내용을 적으면 B도 그 내용을 바로 전달받아 볼 수 있을 것.
-
Shared memory 역시 프로세스끼리 직접 메모리 공간을 공유할 수 있는 것이 아니라 커널에게 시스템 콜을 요청.
출처 : 반효경 교수님(이화여대) 강의
반효경 교수님의 강의를 들으며 정리한 것입니다.
'IT > OS' 카테고리의 다른 글
[OS] 3-2. Process 2 (0) | 2020.12.24 |
---|---|
[OS] 3-1. Process 1 (0) | 2020.12.18 |
[OS] 2-2. System Structure & Program Execution 2 (0) | 2020.12.16 |
[OS] 2-1. System Structure & Program Execution 1 (0) | 2020.12.15 |
[OS] 1. Introduction to Operating Systems (0) | 2020.12.14 |