운영체제(Operating System) 3강

운영체제(Operating System) 3강

반효경 교수님 - Process Management


Lecture



Process Management


Process creation


컴퓨터가 부팅되어 운영체제가 실행된 후 최초의 프로그램을 실행할 때 다음과 같은 과정이 발생한다. (단순 예시임 !)


  1. 컴퓨터를 부팅한다.
  2. 아무것도 하지 않고 즉시 바탕화면에 있는 League of Legends.exe를 더블클릭한다.
  3. 운영체제는 메모리에 League of LegendsData, Code영역을 로딩하고, 빈 Stack을 생성한 후 PCB를 하나 새로 만들어 초기화한다.
  4. 금방 실행한 최초의 프로세스는 0번 프로세스이다.


위의 과정은 컴퓨터가 부팅 된 후 최초의 프로세스를 생성할 때 단 한번만 진행된다.

이후부터 생성되는 프로세스는 0번 프로세스를 복사하여 생성된다.

이 이유는 프로세스를 새로 만드는 것보다 기존의 것을 복사하는게 더 비용이 적게 소모되기 때문이다.


  1. Diablo 2.exe를 실행한다.
  2. 이미 실행중인 League of Legends를 대상으로 운영체제의 fork() 함수를 호출해 복사한다.
  3. 복사된 프로세스의 부모 프로세스는 League of Legends이며, League of Legends의 자식 프로세스는 Diablo 2이다.
  4. 복사된 Diablo 2League of Legends의 데이터들을 갖고 있으므로, 운영체제는 Diablo 2를 대상으로 exec()함수를 호출해 Diablo 2.exe의 모든 데이터를 덮어쓴다.
  5. 이후부터 Diablo 2League of Legends와 다르게 동작하기 시작한다.


위 내용들은 대략적인 예시이며, 실제로 리그오브레전드를 실행할 때 저런 과정이 발생하는것도 아니며, 리그오브레전드를 복사해서 디아블로를 실행한다는 것도 아니다.

분명 리그오브레전드나 디아블로를 실행하기 위해 복사하는 상위의 어떤 프로세스가 있을것이라는 의미이다.

위 과정을 리눅스 터미널에서 새로운 프로세스를 생성하는 것을 대입해 연상하면 조금 더 이해가 쉬울 것 같다.

정리하면 대략 다음과 같다.

  • 새로운 프로세스를 생성할 때, 이미 존재하는 프로세스를 복제한다. 이때 기존 프로세스를 부모 프로세스라 하고, 복제 생성된 프로세스를 자식 프로세스라고 부른다.
  • 프로세스의 계층 구조는 트리로 형성된다.
  • 모든 프로세스들은 컴퓨터 자원을 필요로 한다.
    • 운영체제에게 컴퓨터 자원을 받는다.
    • 프로세스는 자원을 부모와 공유할 수 있다.
  • 프로세스간 자원 공유 모델은 러프하게 다음과 같다.
    • 부모와 자식이 모든 자원을 공유하는 모델
    • 일부를 공유하는 모델
    • 전혀 공유하지 않는 모델
    • 부모와 자식이 공존하며 수행하는 모델 (이때는 부모자식간에 CPU를 획득하기 위한 경쟁이 일어날 수 있음)
    • 자식이 종료(Terminate)될 때까지 부모가 기다리는(Wait) 모델


Process termination


  • 자식 프로세스가 부모 프로세스에게 exit() 함수를 통해 종료 신호를 보낸다.
  • 부모 프로세스는 자식 프로세스의 종료 신호를 인지하고 자식 프로세스를 종료시킨다.
  • 종료된 프로세스의 자원들이 운영체제에 반납된다.
  • 부모 프로세스가 abort() 함수를 통해 자식 프로세스를 강제로 종료하는 경우도 있다.
    • 자식 프로세스가 사용하는 자원이 할당된 자원의 한계치를 넘어서는 경우
    • 자식에게 할당된 작업이 더 이상 필요하지 않은 경우
    • 부모 프로세스가 종료되는 경우

만약 부모 프로세스가 비정상적으로 종료되거나, 자식 프로세스가 비정상적으로 종료되 exit()신호를 부모 프로세스에게 주지 못한 경우, 이 프로세스는 정상종료 되지 못하고 컴퓨터의 자원만 점유하며 남아있는 경우가 발생 할 수 있다.

이를 좀비 프로세스(Zombie Process)라 부르며, 컴퓨터를 오래 켜두면 느려지는 이유 중 하나가 바로 이 좀비 프로세스가 많아지는 것 때문이기도 하다.

exit() 는 프로세스가 종료 될 때 운영체제에게 자신의 작업이 끝났음을 알리는 자발적 종료(Non-Preemptive, 비선점)에 해당하는 시스템 콜이다.

그리고, abort() 는 부모 프로세스가 자식 프로세스를 강제로 종료하는 것이기에, 비자발적 종료(Preemptive, )에 해당하는 시스템 콜이다.

여기서 PreemptiveNon-Preemptive 라는 용어는 앞으로도 자주 나올 것이기 때문에 잘 기억해두자.


System Call

fork()


  • 운영체제는 효율적인 프로세스의 생성을 위해 fork() 시스템 콜을 제공한다.
  • 프로세스가 해당 시스템 콜을 호출하면 CPU의 제어권이 커널로 넘어가고, 커널은 fork() 를 호출한 프로세스를 복제하여 자식 프로세스를 생성한다.
  • fork() 를 수행하면 부모 프로세스의 주소 공간을 비롯해 각종 레지스터의 현재 상태, PCB 등의 모든 문맥을 그대로 복제해 자식 프로세스의 문맥으로 형성한다.
  • 따라서 자식 프로세스는 부모 프로세스의 처음부터 수행하지 않고, 부모 프로세스가 현재 수행해야 할 시점부터 수행하게 된다.
  • 다만 운영체제가 프로세스를 관리해야 하기 때문에 자식 프로세스와 부모 프로세스의 식별자(PID)는 다르다.


image


  • 부모 프로세스가 메인 함수의 첫 번째 줄부터 한 줄씩 코드를 수행하다가 fork() 라인에 이르면 자신과 똑같은 프로세스를 하나 생성한다.
  • 이때 fork() 라인까지 수행했다는 기억조차도 똑같은 자식 프로세스가 생성된다. 즉, 금방 생성된 자식 프로세스는 여지껏 부모 프로세스가 수행한 작업을 자신이 한 것으로 알고있음이다.
  • 그래서 복제된 프로세스는 자기가 복제본이 아니라 원본이며, 자기를 복제해서 다른 복제본을 생성했다는 기억을 갖고 있다.
  • 다만 이 자식 프로세스가 복제된 프로세스라는 사실을 알 수 있는 단서가 있는데, 진짜 부모 프로세스는 fork()의 반환값으로 0보다 큰 값을 반환하고, 자식 프로세스는 fork() 의 반환값으로 값으로 0을 반환한다.


exec()


  • fork() 만으로는 같은 코드에 대해 조건을 분기하는 정도로 밖에 사용할 수 없다.
  • 자식 프로세스에게 부모 프로세스와는 독자적인 작업을 수행할 수 있게 하는 시스템 콜이 바로 exec() 이다.
  • 이 시스템 콜은 프로세스의 메모리에 새로운 프로그램의 데이터를 덮어 씌운 후, 덮어 씌운 새로운 프로그램의 첫 부분부터 다시 실행하도록 한다.
  • 즉, 새로운 프로그램을 수행하기 위해서는 fork() 로 자식 프로세스를 생성한 뒤, exec() 로 해당 프로세스의 주소 공간을 새롭게 수행하려는 프로세스의 주소 공간으로 덮어 씌우면 된다.


image


  • execlp() 라인에 이르면 새로운 프로그램으로 덮어 씌운다.


wait()


image


  • 자식 프로세스가 종료되기를 기다리며 부모 프로세스가 Wait 상태에 머무르도록 할 때 사용한다.
  • 부모 프로세스가 fork() 후에 wait() 을 호출하면 자식 프로세스가 종료될 때까지 부모 프로세스를 Wait 상태에 머무르게 하고, 자식 프로세스가 종료되면 부모 프로세스를 Ready 상태로 변경한다.


exit()


image


  • 프로세스를 자발적으로 종료할 때 사용한다.
  • 프로그램에 명시적으로 적어주지 않아도 프로세스의 main 함수가 리턴되는 위치에 컴파일러가 자동으로 넣어준다.


abort()


  • 프로세스를 비자발적으로 종료할 때 사용한다.
  • 부모 프로세스가 자식 프로세스를 강제로 종료한다.
    • 자식 프로세스가 한계를 넘어서는 자원을 요청하는 경우
    • 자식에게 할당된 작업이 더 이상 필요하지 않은 경우
  • 터미널에서 kill, break 등의 명령어를 입력한 경우
  • 부모가 종료하는 경우
    • 부모 프로세스가 종료하기 전에 자식들이 먼저 종료됨.
    • dontKillMe 옵션을 주면 자식 프로세스는 종료되지 않는다.


Collaboration between processes

독립적 프로세스 (Independent process)


프로세스는 각자의 메모리를 가지고 동작하므로 원칙적으로 하나의 프로세스는 다른 프로세스의 수행에 영향을 미치지 못한다. (메모리 관리자가 프로세스간의 메모리 침범을 허용하지 않는다.)


협력 프로세스 (Cooperating process)


  • 프로세스 협력 메커니즘을 통해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수도 있다.


프로세스 간 협력 메커니즘 (IPC: Interporcess Communication)



  • IPC는 프로세스들 간의 통신과 동기화를 이루기 위한 메커니즘을 의미한다.
  • 크게 메시지 전달 방식과 공유 메모리 방식이 있다.
  • TCP 등의 프로토콜을 사용한 프로세스간의 통신도 IPC의 일종이며, 소켓 통신이라고도 불린다.


메시지 전달 방식 (Message Passing)


image


  • 직접 통신 (Direct Communication)

    • 통신하려는 프로세스의 이름을 명시적으로 표시한다.
    • 각 쌍의 프로세스에게는 오직 하나의 링크만 존재한다.


  • 간접 통신 (Indirect Communication)

    • 메시지를 메일 박스 또는 포트로부터 전달받는다.
    • 각 메일 박스에는 고유의 ID가 있으며 메일 박스를 공유하는 프로세스만 통신할 수 있다.
    • 하나의 링크가 여러 프로세스에게 할당될 수 있다.


공유 메모리 방식 (Shared Memory)


image


  • 공유 메모리 방식은 프로세스들이 주소 공간의 일부(Heap 등)를 공유한다.
  • 동시성으로 인해 데이터 정합성 문제가 발생할 수 있다.
  • 따라서 프로세스 간 동기화(synchronization) 문제를 스스로 책임져야 한다.



© 2022. All rights reserved.