Os 4 Process Management
프로세스 생성(Process Creation)
운영체제가 프로세스를 모두 생성하지 않는다. 부팅 후 최초 프로세스는 운영체제가 생성하지만 그 다음부터는 이미 존재하는 프로세스가 다른 프로세스를 복제 생성한다.
이때 부모 프로세스가 자식 프로세스를 생성하면서 족보와 같은 계층을 형성한다. 부모 프로세스는 자식 프로세스가 먼저 죽고 부모 프로세스가 종료된다.
생성된 프로세스가 작업을 수행하려면 자원이 필요하다. 운영체제로부터 직접 자원을 할당받을 수도 있고 부모 프로세스와 자원을 공유할 수도 있다.
프로세스가 수행되는 모델도 부모와 자식이 공존하며 수행되는 모델과 자식이 종료(Terminate)될 때까지 부모가 기다리는(wait) 모델이 있다.
부모와 자식이 공존하며 수행하는 모델에서는 CPU를 획득하기 위한 경쟁 관계다. 부모가 자식의 종료를 기다리는 모델에서는 자식 프로세스가 종료될 때까지 부모 프로세스는 아무 일도 하지 않는 봉쇄 상태에 머물다가 자식 프로세스가 준비 상태가 되면 CPU을 얻을 권한이 생긴다. 이를테면 유닉스 명령어 입력창에 커맨드를 입력하면 종료될 때까지 다시 프롬프트를 띄우지 않는 사례를 들 수 있다.
프로세스가 생성되면 자신만의 독자적인 주소 공간을 갖는다. 자식은 부모와 별도의 주소 공간을 가지게 되는데 처음 주소 공간을 생성할 내용은 부모 프로세스 공간 내용을 그대로 복사해서 생성된다. 자식 프로세스가 다른 프로그램을 수행하려면 생성된 주소 공간 위에 새로운 프로그램의 주소 공간을 덮어씌워 실행하는 것이다.
유닉스에서는 fork()
시스템 콜을 통해 새로운 프로세스를 생성한다. 이는 프로세스 ID를 제외한 모든 정보(운영체제 커널 내의 정보와 주소 공간의 정보)를 그대로 복사하는 방법을 사용한다. fork()
를 통해 생성된 자식 프로세스는 exec()
시스템 콜을 통해 새로운 프로그램을 주소 공간을 덮어씌울 수 있다.
Who: 부모 프로세스가 자식 프로세스 생성
- 프로세스의 트리(계층 구조) 형성
- 삼각형 형태의 족보같은 구조
- 프로세스는 자원을 필요로 함
- 운영체제로부터 받는다.
- 부모와 공유한다.
- 자원의 공유
- 부모와 자식이 모든 자원을 공유하는 모델
- 일부를 공유하는 모델
- 전혀 공유하지 않는 모델(일반적)
- 일반적으로 서로 CPU를 얻으려는 경쟁상태가 되므로 공유하지 않는다.
- 수행(Execution)
- 부모와 자식은 공존하며 수행되는 모델
- 자식이 종료(terminate)될 때까지 부모가 기다리는 모델
How: 복제 생성
- 일단 복제한 후(fork) 그 위에 새로운 프로그램을 올리는 것(exec)
- fork나 exec(시스템콜)는 OS가 수행
- 주소 공간
- 자식은 부모의 공간을 복사함(binary and OS data)
- 자식은 그 공간에 새로운 프로그램을 올림
- 유닉스의 예
fork()
시스템 콜이 새로운 프로세스를 생성- 부모를 그대로 복사(OS data except PID + binary)
- 주소 공간 할당
- fork 다음에 이어지는
exec()
시스템 콜을 통해 새로운 프로그램을 메모리에 올림
프로세스 종료(Process Termination)
유닉스에서는 부모 프로세스가 종료되기 전에 아래 자식 프로세스들이 먼저 종료되어야 한다. 프로세스 종료는 두 가지로 나뉜다.
첫 번째는 프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려 이뤄지는 자발적 종료다. 프로세스는 명령(instruction)을 모두 수행한 후 프로그램이 마쳐지는 코드 부분에 exit()
라는 시스템 콜을 넣어주도록 되어 있다.
한편 exit()
함수는 개발자가 명시적으로 호출하지 않아도 프로그램이 종료되는 지점에 컴파일러가 자동으로 삽입해 종료 직전에 항상 호출된다.
두 번째는 비자발적 종료로 부모 프로세스가 자식 프로세스의 수행을 강제로 종료시킨다. 이는 abort()
라는 함수를 통해 이뤄진다. 강제종료가 발생하는 경우는 다음과 같다.
- 자식 프로세스가 할당 자원의 한계치를 넘어서는 많은 양의 자원을 요구할 때
- 자식 프로세스에게 할당된 작업이 더이상 필요하지 않을 때
- 부모 프로세스가 종료되는 경우
한편 로그아웃 후에도 계속 프로세스를 수행시켜야 하는 경우 자식 프로세스를 존재하는 다른 프로세스로 보내 기존 부모 프로세스가 종료된 후에도 다른 프로세스 아래 계속 수행될 수 있도록 하기도 한다.
fork()
시스템 콜
- 1)
fork()
를 하면 자식 프로세스가 생성되고 - 2) 자식 프로세스는 이전 코드의 문맥(부모 프로세스의 주소 공간을 비롯한 프로그램 카운터 등 레지스터 상태, PCB, 커널스택)은 그대로 복사하므로 실행하지 않고 그 이후를 실행한다.
- 3)
fork()
이후 부모PID > 0
, 자식PID = 0
으로 구별
fork()
시스템 콜을 통해 프로세스를 생성한 후 그 결괏값에 따라 부모 프로세스와 자식 프로세스에게 다른 작업을 수행시킬 수 있지만 이는 조건문에 의한 분기일 뿐 사실상 두 프로세스 모두 동일한 코드다.
따라서 자식 프로세스에게 독자적 프로그램을 수행시키기 위해 프로세스의 주소 공간에 새로운 프로그램을 덮어씌우는 exec()
시스템 콜을 지원한다.
exec()
시스템 콜
지금까지 수행했던 상태를 잊어버리고 그 주소 공간을 완전히 새로운 프로그램으로 덮어씌운 후 새로운 프로그램의 첫 부분부터 다시 실행을 시작하도록 하는 시스템 콜이다.
따라서 새로운 프로그램을 수행하려면 fork()
를 통해 기존 프로세스와 동일한 프로세스를 복제한 후 exec()
로 새롭게 수행시키려는 프로세스를 자식 프로세스의 주소 공간에 덮어씌운다.
- 1)
execlq()
를 실행하면 그 이전 기억은 다 잊어버리고 새롭게 시작 - 2) 한 번 이그젝하면 그 이전으로 돌아갈 수 없다.
- 3) 이그젝 이후의 코드는 실행되지 않을 것?
wait()
시스템 콜
자식 프로세스가 종료되기를 기다리며 부모 프로세스가 봉쇄 상태에 머무르게 할 때 사용된다.
fork()
후에 wait()
을 호출하면 커널은 자식 프로세스가 종료될 때까지 부모 프로세스를 봉쇄 상태에 머무르게 하고 자식 프로세스가 종료되면 부모를 준비 상태로 변경시켜 작업을 재개할 수 있도록 한다.
이러한 방식으로 부모 프로세스와 자식 프로세스 간의 동기화(synchronization)이 가능해진다.
- 프로세스 A가
wait()
시스템 콜을 호출하면- 커널은 자식이 종료될 때까지 프로세스 A를 Sleep시킨다(block 상태)
- 자식 프로세스가 종료되면 커널은 프로세스 A를 깨운다(ready 상태)
- 예) 커맨드 라인에서 명령어를 치면 명령어를 띄웠던 부모 프로세스는 명령어를 실행하는 자식 프로세스가 끝날 때까지 기다린다.
exit()
시스템 콜
프로세스의 종료
- 자발적 종료
- 메인 함수의 괄호를 닫으면 암시적으로 프로세스 종료
- 비자발적 종료
- 부모 프로세스가 자식 프로세스 강제 종료
- 자식 프로세스 한계치 넘어서는 자원요청
- 자식에게 할당된 태스크가 더이상 필요하지 않음
- kill, break 등 강제 종료
- 부모가 종료하는 경우 자식들을 먼저 종료시킴
- 부모 프로세스가 자식 프로세스 강제 종료
프로세스 간 협력
프로세스는 독립적인 주소 공간을 가지고 수행되며 프로세스가 다른 프로세스의 주소 공간을 참조하는 것은 허용되지 않는다.
운영체제는 프로세스 간의 협력 메커니즘을 제공해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있게 한다.
- 독립적 프로세스(Independent process)
-
프로세스는 각자의 주소 공간을 가지고 수행되므로 원칙적으로 하나의 프로세스는 다른 프로세스의 수행에 영향을 미치지 못함
- 협력 프로세스(Cooperating process)
- 프로세스 협력 메커니즘을 통해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있음
프로세스 간 협력 메커니즘(IPC: Interprocess Communication)
프로세스 간 협력 메커니즘을 위해 운영체제가 제공하는 대표적인 것으로 IPC(Interprocess Communication)가 있다. IPC란 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신을 말한다.
이러한 통신에서는 의사소통 기능과 함께 동기화를 보장해주어야 한다. 공유 데이터를 두 프로세스가 사용하면 데이터 불일치 문제가 발생할 수 있기 때문이다.
IPC는 프로세스들 간 통신과 동기화를 이루기 위한 메커니즘을 말하는데 대표적으로 메시지 전달(message passing) 방식과 공유메모리(shared memory) 방식이 있다.
메시지 전달 방식은 프로세스 간에 공유 데이터를 일체 사용하지 않고 메시지를 주고받으면서 통신하는 방식이다. 이때 메시지 전달은 커널이 담당한다. 통신을 원하는 두 프로세스는 커뮤니케이션 링크를 생성한 후 send(message)
와 receive(message)
의 두 가지 연산을 시스템 콜 방식으로 요청해 메시지를 전달한다.
메시지 전달을 통한 통신 방식은 메시지 전송 대상이 다른 프로세스인지 메일박스라는 일종의 저장공간인지에 따라 다시 직접통신(direct communication)과 간접통신(indirect communication)으로 나뉜다.
메시지 전달방식
- message passing: 커널을 통해 메시지 전달
- 프로세스는 독립적이므로 직접 메시지를 전달하지 못하고 커널을 통해 전달
- Direct : 통신하려는 이름을 명시
send(P, message)
,receive(Q, message)
- 각 쌍의 프로세스에게는 오직 하나의 링크만 존재, 링크는 단방향성일 수 있으나 대부분 양방향성
- Indirect : 통신하려는 이름을 명시 X, 우체통(or port)에 메시지를 넣는다.
- 각 메일박스에는 고유한 ID가 있으며 메일 박스를 공유하는 프로세스들만 서로 통신할 수 있다.
- 커뮤니케이션 링크는 프로세스 간 메일박스를 공유하는 경우에만 생성
- 하나의 링크가 여러 프로세스들에게 할당될 수 있으며 각 프로세스 쌍은 여러 링크를 공유할 수 있다.
- 링크는 단방향, 양방향 모두 가능
공유 메모리 방식
- shared memory: 서로 다른 프로세스 간에도 일부 주소 공간을 공유
- 처음에는 커널에 메모리 공유공간을 쓴다고 알려야 함
- 운영체제는 공유메모리를 사용하는 시스템 콜을 지원
- 이러한 공유 메모리 영역은 각자의 주소 공간에 공통적으로 포함되는 영역이므로 여러 프로세스가 읽고 쓰는 것이 가능
- 물리적 메모리로 매핑될 때 공유메모리 주소 영역은 동일한 물리적 메모리 주소로 매핑
- thread: 쓰레드는 사실상 하나의 프로세스이므로 프로세스 간 협력으로 보기는 어렵지만 동일한 프로세스를 구성하는 스레드 간에는 주소 공간을 공유해 협력 가능