[운영체제와 정보기술의 원리] 5. 프로세스 관리

'운영체제와 정보기술의 원리' 스터디를 진행하며 정리한 내용이다.


1. 프로세스의 개념

  • 프로세스(process)란 실행 중인 프로그램(program in execution)을 뜻한다.
  • 디스크에 실행파일 형태로 존재하던 프로그램이 메모리에 올라가서 실행되기 시작하면 프로세스가 되며, 프로세스는 CPU를 획득해 자신의 코드를 수행하기도 하고, 때로는 CPU를 반환하고 입출력 작업을 수행하기도 함.
  • 일반적으로 잡(job)이라는 용어와 프로세스를 혼용해 사용하기도 함.
  • 프로세스의 문맥(context)이란 프로세스가 현재 어떤 상태에서 수행되고 있는지 정확히 규명하기 위해 필요한 정보를 의미한다.

    • 시분할 시스템과 같은 환경에서는 CPU를 다시 획득해 명령의 수행을 재개하는 시점이 되면 이전의 CPU 보유 시기에 어느 부분까지 명령을 수행했는지 직전 수행 시점의 정확한 상태를 재현할 필요가 있고 이를 위해 필요한 정보가 문맥임.
    • 문맥은 크게 세 가지로 분류가 가능함.
    • 하드웨어 문맥

      • CPU의 수행 상태를 나타내는 것으로 프로그램 카운터값과 각종 레지스터에 저장하고 있는 값들을 의미
    • 프로세스의 주소 공간

      • 코드, 데이터, 스택으로 구성되는 자기 자신만의 독자적인 주소 공간.
    • 커널상의 문맥

      • 프로세스를 관리하기 위한 자료구조인 PCB와 커널스택

2. 프로세스의 상태

  • 프로세스의 상태는 실행(running), 준비(ready), 봉쇄(blocked, wait, sleep) 세 가지로 구분할 수 있음. + 시작(new), 완료(terminated) 상태

    Untitled (72)

    • 실행 상태 - 프로세스가 CPU를 보유하고, 기계어 명령을 실행하고 있는 상태
    • 준비 상태 - 프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있지만 CPU를 할당받지 못한 상태
    • 봉쇄 상태 - CPU를 할당받더라도 당장 명령을 실행할 수 없는 상태 ex) 입출력 작업
    • 시작 상태 - 프로세스가 시작되어 그 프로세스를 위한 각종 자료구조는 생성되었지만 아직 메모리 획득을 승인받지 못한 상태
    • 완료 상태 - 프로세스가 종료되었으나 운영체제가 그 프로세스와 관련된 자료구조를 완전히 정리하지 못한 상태
  • 실행시킬 프로세스를 변경하기 위해 원래 수행 중이던 프로세스의 문맥을 저장하고 새로운 프로세스의 문맥을 세팅하는 과정을 문맥교환(context switch)이라고 한다.

    • ex) 타이머 인터럽트, 입출력 요청 등
  • 준비 상태에 있는 프로세스들 중에서 CPU를 할당받을 프로세스를 선택한 후 실제로 CPU 제어권을 넘겨받는 과정을 CPU 디스패치(dispatch)라고 한다.
  • 인터럽트가 발생하면 CPU는 어떤 프로세스를 실행하고 있다가 인터럽트를 확인하고 그에 대응하는 루틴을 실행함. 루틴이 진행되는 동안 CPU에서 수행되던 프로세스의 상태는 커널모드 실행 상태로 바뀜. 인터럽트 처리루틴이 직전에 실행 중이던 프로세스와는 무관한 업무를 담고 있기는 하지만 인터럽트 처리를 편의상 직전 프로세스의 문맥에서 실행된 것으로 간주함.

3. 프로세스 제어블록

  • 프로세스 제어블록(PCB)이란 운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내의 자료구조를 뜻함.
  • PCB는 다음과 같은 요소들로 구성되어 있음.

    • 프로세스 상태 - CPU를 할당해도 되는지 여부를 결정하기 위해 필요
    • 프로그램 카운터값 - 다음에 수행할 명령의 위치
    • CPU 레지스터값 - CPU 연산을 위해 현 시점에 레지스터에 어떤 값을 저장하고 있는지를 나타냄.
    • CPU 스케줄링 정보 - 프로세스의 CPU 스케줄링을 위해 필요한 정보
    • 메모리 관리 정보 - 메모리 할당을 위해 필요한 정보
    • 자원 사용 정보 - 자원 사용 요금을 계산해 청구하는 등의 용도로 사용.
    • 입출력 상태 정보 - 프로세스가 오픈한 파일 정보 등 프로세스의 입출력 관련 상태 정보

4. 문맥교환

  • 문맥교환이란 하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU 제어권이 이양되는 과정을 뜻함.

    • 문맥교환 중에 원래 CPU를 보유하고 있던 프로세스는 프로그램 카운터값 등 프로세스의 문맥을 자신의 PCB에 저장하고, 새롭게 CPU를 할당받을 프로세스는 예전에 저장했던 자신의 문맥을 PCB로부터 실제 하드웨어로 복원시키는 과정을 거친다.
    • 타이머 인터럽트, 입출력 요청, 다른 조건을 충족하지 못해 CPU를 회수당하고 봉쇄 상태가 되는 경우 등에서 발생.
  • 시스템 콜(입출력 요청 시스템 콜이 아님)이나 인터럽트의 경우에도 CPU의 실행 위치 등 프로세스의 문맥 중 일부를 PCB에 저장하게 되지만 이러한 과정을 문맥교환이라고 하지는 않음.

    • 사용자모드에서 커널모드로 바뀌는 것일뿐, CPU를 점유하는 프로세스가 다른 사용자 프로세스로 변경되는 과정이 아니기 때문.
    • 모드 변경에 비해 문맥교환에는 훨씬 많은 오버헤드가 뒤따르게 됨.
  • 타이머 인터럽트, 입출력 요청 시스템 콜을 하여 봉쇄 상태에 들어가는 경우에는 문맥교환이 일어나지만, 그 밖의 인터럽트나 시스템 콜 발생 시에는 문맥교환이 일어나지 않고 실행 모드만이 변경될 뿐임.

    • 사용자모드에서 커널모드로 바뀌어 시스템 콜이나 인터럽트를 처리하고, 다시 동일한 프로세스의 사용자모드로 돌아와 이전에 수행하던 작업을 계속 수행할 뿐.
  • 타이머에 CPU 할당시간을 아주 작게 세팅해 프로세스 간 문맥교환이 빈번하게 발생하도록 하면 오버헤드가 상당히 커지고 CPU 할당시간을 너무 크게 설정하면 시분할 시스템의 의미가 퇴색하게 되므로 적절한 CPU 할당시간을 정하는 것이 중요함.

5. 프로세스를 스케줄링하기 위한 큐

  • 운영체제는 준비 상태에 있는 프로세스들을 줄 세우기 위해 준비 큐(ready queue)를 두고 준비 큐의 제일 앞에 줄 서 있는 프로세스에 제일 먼저 CPU를 할당함.

    • 준비 큐에 프로세스를 줄 세우는 방법은 CPU 스케줄링 방법에 따라 달라짐.
  • 특정 자원을 기다리는 프로세스들을 줄 세우기 위해 자원별로 장치 큐(device queue)를 둔다.

    • 디스크에 입출력 서비스를 요청한 프로세스들은 디스크 입출력 큐(disk I/O queue)에 줄 서게 됨.
    • 인터럽트 처리루틴에 의해 디스크 입출력이 완료된 프로세스는 입출력 큐에서 빠져나와 CPU를 기다리는 준비 큐에 줄 서게 됨.
  • 하드웨어 자원을 기다리는 프로세스 외에도 소프트웨어 자원을 기다리는 경우에도 큐가 필요함.

    • 공유 데이터에 대한 접근 권한은 소프트웨어 자원으로 분류될 수 있음.
    • 공유 데이터라는 일종의 소프트웨어 자원을 앞서 접근 중인 프로세스가 다 사용하고 반납할 때까지는 다른 프로세스가 CPU를 할당받았다 하더라도 접근하지 말고 기다려야 하는 것.
    • 따라서 여러 프로세스가 공유 데이터에 접근하려고 할 경우 기다리는 큐에 줄 서게 하고, 다른 프로세스가 데이터를 반납할 경우 큐에 줄 서 있는 순서대로 데이터의 접근 권한을 주는 방법을 사용하게 됨.
  • 프로세스의 상태 관리는 커널의 주소 영역 중 데이터 영역의 다양한 큐를 두어 수행하게 됨.
  • 준비 큐와 장치 큐 외에 작업 큐(job queue)를 추가로 유지함.

    • 작업 큐는 시스템 내의 모든 프로세스를 관리하기 위한 큐로, 프로세스의 상태와 무관하게 현재 시스템 내에 있는 모든 프로세스가 작업 큐에 속하게 됨. 그러므로 작업 큐에 있다고 해서 반드시 메모리를 가지고 있는 것이 아님.
    • 작업 큐가 가장 넓은 개념이고 준비 큐와 장치 큐에 있는 프로세스들은 모두 작업 큐에 속해있음.
  • 큐헤더는 큐의 가장 앞부분을 말하고 큐는 각 프로세스의 PCB를 연결 리스트 형태로 관리하며 포인터를 사용해 순서를 정함.

6. 스케줄러

  • 스케줄러(scheduler)란 어떤 프로세스에게 자원을 할당할지를 결정하는 운영체제 커널의 코드를 지칭함.
  • 장기 스케줄러(long term scheduler)

    • 작업 스케줄러(job scheduler)
    • 어떤 프로세스를 준비 큐에 진입시킬지를 결정하는 역할을 함.
    • 프로세스에게 메모리를 할당하는 문제에 관여하게 됨.
    • 즉, 시작 상태의 프로세스들 중 어떠한 프로세를 준비 큐에 삽입할 것인지 결정하는 역할을 하게 되는 것.
  • 단기 스케줄러(short term scheduler)

    • CPU 스케줄러
    • 준비 상태의 프로세스 중에서 어떤 프로세스를 다음번에 실행 상태로 만들 것인지 결정함.
    • 즉, 준비 큐에 있는 여러 프로세스들 중 어떠한 프로세스에게 CPU를 할당할 것인가를 단기 스케줄러가 결정함.
    • 시분할 시스템에서는 타이머 인터럽트가 발생하면 단기 스케줄러가 호출됨.
  • 단기 스케줄러는 밀리초 정도의 시간 단위로 매우 빈번하게 호출되기 때문에 속도가 충분히 빨라야하는 반면에 장기 스케줄러는 수십 초 내지 수 분 단위로 가끔 호출되기 때문에 상대적으로 속도가 느린 것이 허용됨.
  • 장기 스케줄러는 메모리에 동시에 올라가 있는 프로세스의 수를 조절하는 역할을 함.
  • 현대 시분할 시스템에서 사용되는 운영체제에는 일반적으로 장기 스케줄러를 두지 않는 경우가 대부분임.

    • 과거에는 자원이 매우 빈약했지만 현대에는 그렇지도 않아 프로세스가 시작 상태가 되면 곧바로 프로세스에 메모리를 할당해 준비 큐에 넣어주게 됨.
  • 중기 스케줄러(medium term scheduler)

    • 너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 경우 이를 해결하기 위해 메모리에 적재된 프로세스의 수를 동적으로 조절하기 위해 추가된 스케줄러.
    • 메모리에 올라와 있는 프로세스 중 일부를 선정해 이들로부터 메모리를 통째로 빼앗아 그 내용을 디스크의 스왑 영역에 저장해두는데 이를 스왑 아웃(swap out)이라고 부름.
    • 스왑 아웃시킬 0순위 프로세스는 봉쇄 상태에 있는 프로세스.

      • 봉쇄 상태인 프로세스를 모두 스왑 아웃시킨 후에도 부족한 경우, 타이머 인터럽트가 발생해 준비 큐로 이동한 프로세스를 추가적으로 스왑 아웃시킴.
    • 장기 스케줄러와 마찬가지로 메모리에 올라와 있는 프로세스의 수를 조절하는 역할을 수행
  • 중기 스케줄러의 등장으로 인해 프로세스의 상태에는 중지(suspended, stopped) 상태가 추가됨.

    Untitled (73)

    • 중지 상태는 외부적인 이유로 프로세스의 수행이 정지된 상태를 나타내며 외부에서 재개시키지 않는 이상 다시 활성화될 수 없으므로 메모리 자원이 당장 필요하지 않다. 따라서 메모리를 통째로 빼앗기고 디스크로 스왑 아웃됨.
    • 중지 상태는 중지준비 상태와 중지봉쇄 상태로 세분화할 수 있음.
    • 준비 상태에 있던 프로세스가 스왑 아웃되면 중지준비(suspended ready) 상태가 됨.
    • 봉쇄 상태에 있던 프로세스가 스왑 아웃되면 중지봉쇄(suspended block) 상태가 됨.
    • 중지봉쇄 상태이던 프로세스가 봉쇄되었던 조건을 만족하게 되면 중지준비 상태로 바뀜.

7. 프로세스의 생성

  • 운영체제가 프로세스를 전부 생성한다고 생각할 수 있지만 사실은 그렇지 않음.
  • 최초의 프로세스는 운영체제가 직접 생성하지만 그다음부터는 이미 존재하는 프로세스가 다른 프로세스를 복제 생성하게 됨.

    • 프로세스를 생성한 프로세스를 부모 프로세스라고 하고, 새롭게 생성된 프로세스를 자식 프로세스라고 함.
  • 프로세스의 세계는 자식이 먼저 죽고, 이에 대한 처리는 자식을 생성했던 부모 프로세스가 담당하는 방식으로 진행됨.
  • 생성된 프로세스가 작업을 수행하기 위해서는 자원이 필요한데 자원을 획득하는 방법은 운영체제 및 자원의 종류에 따라 상이함.

    • 운영체제로부터 직접 자원을 할당
    • 부모 프로세스와 자원을 공유해서 사용
  • 프로세스가 수행되는 모델도 부모와 자식이 공존하며 수행되는 모델과 자식이 종료될 때까지 부모가 기다리는 모델이 있음.

    • 부모와 자식이 공존하며 수행되는 모델에서는 자식과 부모가 같이 CPU를 획득하기 위해 경쟁하는 관계가 됨.
    • 부모가 자식의 종료를 기다리는 모델에서는 자식 프로세스가 종료될 때까지 부모 프로세스는 아무 일도 하지 않고 봉쇄 상태에 머물러 있다가, 자식 프로세스가 종료되면 그때 부모 프로세스가 준비 상태가 되어 다시 CPU를 얻을 권한이 생김.

      • ex) 유닉스 명령어 입력창에 커맨드를 입력하는 경우
  • 프로세스가 생성되면 자신만의 독자적인 주소 공간을 갖게 됨.

    • 자식 프로세스는 부모 프로세스와는 별도의 주소 공간을 가지게 됨.
  • 유닉스로 살펴보는 프로세스의 생성 절차

    • fork() 시스템 콜을 통해 새로운 프로세스를 생성함.

      • 자식 프로세스를 생성할 때 부모 프로세스의 내용을 그대로 복제 생성. 즉, 프로세스 ID를 제외한 모든 정보(운영체제 커널 내 정보, 주소 공간의 정보)를 그대로 복사함.
      • 주소 공간은 다르지만 주소 공간 내에는 동일한 내용을 가지게 됨.
    • fork()를 통해 생성된 자식 프로세스는 exec() 시스템 콜을 통해 새로운 프로그램으로 주소 공간을 덮어씌울 수 있음.
  • 프로세스의 종료는 두 가지로 나뉨.

    1. 프로세스가 마지막 명령을 수행한 후 운영체제에 이를 알려주는 자발적 종료.

      • 프로세스가 명령을 모두 수행한 후, 프로그램이 마쳐지는 코드 부분에 exit()라는 시스템 콜을 넣어주도록 되어 있음.
    2. 부모 프로세스가 자식 프로세스의 수행을 강제로 종료시키는 비자발적 종료.

      • 자식 프로세스가 할당 자원의 한계치를 넘어서는 많은 양의 자원을 요구할 때, 자식 프로세스에게 할당된 작업이 더 이상 필요하지 않을 때, 부모 프로세스가 종료되는 경우 등일 때 abort()라는 함수를 통해 이루어지게 됨.
  • 종료되는 프로세스의 자식 프로세스를 계속 실행시키기 위해서 종료되지 않을 다른 프로세스의 양자로 자식 프로세스를 보내는 방법도 있음.
  • 운영체제는 자식 프로세스의 생성을 위해 fork() 시스템 콜을 제공함.

    • fork() 시스템 콜을 하게 되면 CPU 제어권이 커널로 넘어가게 되고, fork() 함수를 호출한 프로세스와 똑같은 프로세스가 하나 생성됨.
    • fork()를 통해 생성된 프로세스는 부모 프로세스와 모든 문맥을 동일하게 가지고 있음.
    • 단, 프로세스를 관리하기 위해서 사용하는 프로세스 식별자는 다른 식별자를 가지게 됨.
    • fork()로 복제한 프로세스는 자기가 복제본이 아닌 원본이며, 자기를 복제해서 복제본이 생성되었다는 그런 기억을 갖게 됨.
    • 단, fork() 함수의 결괏값으로 원본에게는 양수를 주고 복제본에게는 0을 주어서 조건문을 사용해 다른 작업을 하도록 프로그램을 작성할 수 있음.
  • 유닉스에서는 프로세스의 주소 공간에 새로운 프로그램을 덮어씌우는 exec() 시스템 콜을 지원함.

    • exec()는 지금까지 수행했던 상태를 잊어버리고 그 주소 공간을 완전히 새로운 프로그램으로 덮어씌운 후 새로운 프로그램의 첫 부분부터 다시 실행을 시작하도록 하는 시스템 콜.
  • fork(), exec()는 특권명령에 해당하므로 시스템 콜을 통해서만 그 수행이 가능함.
  • 자식 프로세스가 종료되기를 기다리며 부모 프로세스가 봉쇄 상태에 머무르도록 할 때 사용되는 wait() 시스템 콜도 존재함.

    • fork() 후에 wait()를 호출하면 커널은 자식 프로세스가 종료될 때까지 부모 프로세스를 봉쇄 상태에 머무르게 하고, 자식 프로세스가 종료되면 부모를 준비 상태로 변경시켜 작업을 재개할 수 있도록 함.
    • 이를 통해 두 프로세스 간의 동기화(synchronization)가 가능해짐.
    • 일반적인 봉쇄 상태에서처럼 자원을 기다리며 줄 서 있는 것이 아니라 자식 프로세스가 종료되기를 기다리며 수면 상태에 머무르게 되는 것으로, 자식 프로세스가 종료되는 순간 준비 큐에 재진입한다.

8. 프로세스 간의 협력

  • 프로세스는 각자 자신만의 독립적인 주소 공간을 가지고 수행되며 다른 프로세스의 주소 공간을 참조하는 것은 허용되지 않음.
  • 경우에 따라서는 독립적인 프로세스들이 협력할 때 업무의 효율성이 증진될 수 있기 때문에 운영체제는 프로세스 간의 협력 메커니즘을 제공해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있게 함.
  • 대표적인 메커니즘으로 IPC(Inter-Process Communication: 인터프로세스 커뮤니케이션)가 있음.

    • IPC란 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신을 말함.
    • 이러한 통신에는 의사소통 기능과 함께 동기화를 보장해주어야 함.

      • 공유 데이터를 서로 다른 두 프로세스가 사용할 수 있다고 하면 데이터의 불일치 문제가 발생할 수 있기 때문.
      • 하나의 프로세스가 공유 데이터의 값을 변경하는 동안 다른 프로세스는 접근할 수 없게 해야 함.
    • 즉, IPC는 프로세스들 간의 통신과 동기화를 이루기 위한 메커니즘을 뜻함.
    • IPC에는 대표적으로 두 가지 방법이 있는데 공유 데이터를 사용하는가, 그렇지 않는가에 따라 나뉘어진다.
    • 메시지 전달 방식(message passing)

      • 프로세스 간에 공유 데이터를 일체 사용하지 않고 메시지를 주고받으면서 통신하는 방식.
      • 메시지 통신을 하는 시스템은 커널에 의해 send(message)와 receive(message)라는 두 가지 연산을 제공받게 됨.
      • 프로세스끼리 메시지를 직접 주고받는다면 원치 않는 메시지로 인해 악영향을 미칠 수 있으므로 특권명령으로 규정해 커널만 가능하도록 하고 있음.
      • 통신하기를 원하는 두 프로세스는 커뮤니케이션 링크를 생성한 후 send()와 receive()를 이용해서 메시지를 주고받게 됨.
      • 메시지 전달 방식은 메세지 전송 대상이 다른 프로세스인지 아니면 메일박스라는 저장공간인지에 따라 다시 직접통신(direct communication)과 간접통신(indirect communication)으로 나뉨. (인터페이스에 대한 차이일 뿐 내부 구현은 동일한 방식으로 이루어짐)
      • 직접통신

        • 통신하려는 프로세스의 이름을 명시적으로 표시함.
        • 커뮤니케이션 링크는 자동적으로 생성되고 하나의 링크가 한 쌍의 프로세스에게 할당됨.
        • 링크는 단방향일수 있으나 대부분은 양방향성임.
      • 간접통신

        • 메시지를 메일박스 또는 포트로부터 전달받음.
        • 각 메일박스에는 고유의 ID가 있으며 메일박스를 공유하는 프로세스들만 서로 통신을 할 수 있음.
        • 커뮤니케이션 링크는 프로세스 간 메일박스를 공유하는 경우에만 생성되고 하나의 링크가 여러 프로세스들에게 할당될 수 있으며 각 프로세스의 쌍은 여러 링크를 공유할 수 있음.
        • 단방향성 또는 양방향성일 수 있음.
        • 새로운 메일박스를 생성하는 연산, 메일박스를 통한 메시지의 send(), receive(), 메일박스를 삭제하는 연상 등이 사용될 수 있음.
        • 만약 P1, P2, P3가 메일박스 A를 공유하는 경우 P1이 메시지를 보냈다면 P2, P3 중 어느 프로세스가 메시지를 받게 될까?

          • 2개의 프로세스에게만 링크를 할당하는 방법이 사용되거나 링크에 대한 receive() 연산을 매 시점 하나의 프로세스만 수행할 수 있도록 하거나 시스템이 메시지 수신자를 임의로 결정해 누가 메시지를 받았는지 송신자에게 통신해주는 방식이 사용될 수 있다.
    • 공유메모리 방식(shared memory)

      • 프로세스들이 주소 공간의 일부를 공유하는 방식.
      • 서로 다른 프로세스들이 그들의 주소 공간 중 일부를 공유할 수 있도록 함.
      • 공유메모리 영역은 여러 프로세스가 읽고 쓰는 것이 가능함.
      • 공유하다보니 데이터 일관성 문제가 유발될 수 있지만 커널이 이를 책임지지 않기에 프로세스들끼리 직접 동기화 문제를 책임져야 한다.