Skip to content

프로세스의 관리

대부분의 시스템에서 프로세스는 동시에 실행될 수 있고, 이들은 동적으로 생성되거나 삭제될 수 있다.

Process Creation (프로세스 생성)

  • 프로세스는 트리(계층) 구조로 되어있다.

  • 프로세스는 PCB에 저장된 pid(process identifier)값을 통해서 식별되고 관리된다.

  • 또 프로세스는 자원이 필요한데, 자원은 운영체제로 부터 받거나 부모와 공유한다.

  • 프로세스 생성 세부 작업 순서

    1. 새로운 프로세스에 PID 할당
    2. 주소 공간과 PCB 공간 할당
    3. PCB 초기화(프로세스 상태, 카운터 등 초기화, 자원 요청 등)
    4. 링크 걸기 (해당 큐에 삽입)

fork()

프로세스의 생성은 fork() 시스템 콜을 이용한다. fork()를 이용하면 부모를 그대로 복사하여 현재 프로세스와 pid만 다른 프로세스를 생성한다. 즉, 같은 동작을 하는 프로세스가 두 개 존재하게 되며, 새로운 프로세스는 원래의 프로세스 주소 공간의 복사본을 포함한다.

fork는 무거운 시스템 콜이다. 부모 프로세스의 전체 복사본을 생성하고, 이를 자식 프로세스로 실행시키기 때문이다. 따라서 이 수행에 필요한 노력을 줄이기 위해 copy-on-write 기술을 사용한다.

copy-on-write는 copy 작업을 부모나 자식이 쓰기 작업을 하기 전까지 지연시킴으로써 효율성을 높여주는 기술이다. 부모 프로세스가 fork 하여 생긴 자식 프로세스의 page를 공유하다가 자식이 page에 쓰기 작업을 할 때 해당 page만을 copy 하는 방식이다. 이를 통해 전체가 복사되는 현상을 방지한다.

copy-on-write는 프로세스들이 일반적으로 메모리에서 page의 일부분만을 사용한다는 사실을 이용한 기술이다.

반면 단점도 있다. 많은 양의 RAM이 사용되며, copy를 하는 시간이 오래 걸린다. 그리고 프로세스를 copy 하자마자 exec을 통해 새로운 프로그램을 로드하는 경우 단점이 극대화된다.

이러한 단점을 커널이 프로세스의 전체 주소 공간이 아니라 오직 page table만 복사함으로써 극복한다.

exec()

fork() 다음에 이어지는 exec() 시스템 콜은 새로운 프로그램을 메모리에 올려 실행시킨다. exec() 시스템 콜은 어떤 프로그램에 새 정보를 완전히 덮어씌운다.

int main() {
int pid = fork();
if (pid == 0) { // child
exec();
} else { // parent
wait();
}
/* code */
}

이처럼 fork 함수의 반환 값을 이용해서 만약 child인 경우 새로운 프로그램을 실행시키고 싶다면 exec() 시스템 콜을 사용하면 된다. exec() 시스템 콜을 사용하는 경우, 그 뒤의 명령어는 수행하지 않는다. 즉, /* CODE */ 에 해당하는 부분은 수행하지 않는다.

wait

wait() 시스템 콜은, 만약 프로세스 A가 wait()를 호출하면 커널은 자식이 종료될 때까지 A를 Sleep(blocked)시킨다. 그리고 자식 프로세스가 종료되면 커널이 A를 깨워 Ready 상태로 만든다.

따라서 만약 자식이 먼저 수행되기를 원하면 위에 있는 코드처럼 wait()를 else문에 넣어주면 된다.

Process Termination

  1. 자발적 종료

    • 현재 프로세스가 마지막 statement를 수행하면, 운영체제에 exit() 명령어를 통해서 이를 알려준다.
    • 그러면 부모 프로세스가 현재 프로세스의 실행을 종료시키고, wait를 통해 자식으로부터 상태 값(status value)을 수집한다. 프로세스의 각종 자원들은 운영체제에 반납된다.
  2. 비자발적 종료 (kill)

    • 부모 프로세스가 자식 프로세스의 수행을 종료시킬 수도 있다. 자식이 할당된 자원의 한계치를 넘어가거나, 자식에세 할당된 작업이 더 이상 필요하지 않거나, 부모 프로세스가 종료되는 경우이다.
    • 프로세스의 비정상적인 종료로 인해 Zombie process나 Orphan process 같은 유형의 프로세스가 존재할 수 있다.
      • Zombie process는 실행이 끝났지만 프로세스 테이블에 엔트리(Entry)를 가지고 있는, 정보가 메모리에 남아있는 프로세스를 말한다. 프로세스가 종료되었지만 버그나 에러로 인해 해당 프로세스의 부모가 아직 wait를 통해서 상태를 수집하지 못한 경우이다. 모든 프로세스는 아주 잠깐 좀비의 상태로 존재할 수 있다.
      • Orphan process는 부모가 wait를 호출하지 않고 종료되었을 때의 자식 프로세스를 의미한다. 즉, 부모는 종료되었지만 자식은 수행 중인 경우이다. 이런 경우엔 init process가 orphan process들의 새로운 부모로 할당되고, init process가 주기적으로 wait를 호출해서 orphan process들의 exit status를 수집한다.