Post

5장 프로세스 관리

프로세스의 개념



프로세스는 현재 실행중인 프로그램을 뜻하며, 일반적으로 job이라는 용어와 혼용해 사용한다.

프로세스를 이해하기 위해서는 프로세스의 문맥을 파악해야 한다.

프로세스 문맥은 프로세스가 현재 어떤 상태에서 수행되고 있는지를 알기 위해 필요한 정보를 의미한다.

예를 들어, 시분할 시스템에서는 프로세스의 타이머가 지나면 다른 프로세스로 CPU 제어권이 넘어간다.

다시 자기 차례가 왔을 때, 어디까지 수행을 했었는지에 대해 알아야 하는데 여기서 수행 시점프로세스 문맥이라고 볼 수 있다.


process context


크게 3가지로 분류하면 하드웨어 문맥, 프로세스의 주소 공간, 커널상의 문맥으로 나눌 수 있다.

하드웨어 문맥은 프로그램 카운터 값, 레지스터 값들을 의미한다.

프로세스 주소 공간은 스택, 코드, 데이터 영역을 뜻한다.

커널상의 문맥은 PCB나 커널의 스택을 의미한다.






프로세스의 상태



프로세스의 상태는 준비(ready), 실행(running), 봉쇄(blocked, wait, sleep) 3가지로 구분한다.


프로세스 상태 변화도


문맥교환(context switch)란, 실행 시킬 프로세스를 변경하기 위해 원래 수행 중이던 프로세스의 문맥을 저장하고 새로운 프로세스의 문맥을 세팅하는 과정이다.

디스패치(dispatch)란, 준비 상태에 있는 프로세스 중에서 CPU를 할당받을 프로세스를 선택한 후 제어권을 넘겨받는 과정이다.


위의 사진으로 설명이 가능하다.






프로세스 제어블록



PCB는 운영체제가 시스템 내의 프로세스들을 관리하기 위해 필요한 정보들을 저장하는 커널 내의 자료구조이다.

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






문맥교환



문맥교환은 위에서 배웠듯이, 하나의 프로세스에서 다른 프로세스로 CPU의 권한이 이양되는 과정이다.

즉, 입출력 연산 또는 타이머 인터럽트로 인해 CPU의 권한이 다른 프로세스로 넘어가는 것을 문맥 교환이라고 하는 것이다.

주의점은 타이머 인터럽트 외의 인터럽트나 시스템 콜로 인해 커널 모드로 진입하는 즉, 운영체제로 CPU의 권한이 넘어가는, 모드가 바뀌는 경우는 문맥교환으로 보지 않는다.

이는 하나의 프로세스의 실행모드만이 사용자모드에서 커널모드로 바뀌는 것일 뿐, CPU를 점유하는 프로세스가 다른 사용자 프로세스로 변경되는 과정이 아니기 때문이다.


문맥교환은 모드 변경에 비해 훨씬 많은 오버헤드를 발생시키는데, 이는 시스템 입장에서 유용한 작업이 아니다.

따라서 타이머가 너무 작아 잦은 문맥교환이 발생하는 것은 좋지 않으며, 또한 타이머를 너무 길게 설정하는 것도 시분할 시스템의 의미가 퇴색되는 것이므로 적절한 CPU 할당시간을 정하는 것이 중요하다.






프로세스 스케줄링 큐



운영체제는 준비 상태에 있는 프로세스들을 줄 세우기 위해 준비 큐(ready queue)를 가지고 있다.

또한, 장치별로 프로세스들을 줄 세우기 위해 장치 큐(device queue)를 가지고 있다.

예를 들어, 디스크 입출력 연산을 하고자 하면 디스크 입출력 큐에 줄 서게 된다.


위와 같은 큐는 하드웨어 자원을 기다리는 프로세스들을 위한 것이고, 공유 데이터 같은 소프트웨어 자원에 대해서도 큐가 있다.

여러 프로세스가 공유 데이터에 동시에 접근하려고 할 경우 공유 데이터를 기다리는 큐에 줄 서게 하여 현재 그 데이터를 사용중인 프로세스가 완료되기 전까지 접근하지 못하게 하고, 반납하면 차례대로 접근 권한을 준다.


이처럼 프로세스의 상태 관리는 커널의 주소 영역 중 데이터 영역에 다양한 큐를 두어 수행하게 된다.

즉, 커널이 전체적인 프로세스의 정보를 관리한다는 뜻으로 예를 들어, 타이머 인터럽트가 발생하면 커널은 자신의 데이터 영역에 있는 준비 큐의 정보를 참조해 CPU를 누구에게 줄 것인지 결졍하고, 현재 실행 중인 프로세스를 준비 큐의 맨 뒤로 보낸다.


준비 큐, 장치 큐를 포함한 가장 큰 틀인 작업 큐가 있으며 작업 큐는 시스템 내의 모든 프로세스를 관리하기 위한 큐이다.

작업 큐에는 프로세스의 상태와 무관하게 현재 시스템 내에 있는 모든 프로세스가 작업 큐에 속한다.

즉, 작업 큐 안에서 세부적으로 준비 상태 프로세스들은 준비 큐로, 입출력 대기 프로세스들은 장치 큐로 가는 것이다.






스케줄러



스케줄러어떤 프로세스에게 자원을 할당할지를 결정하는 운영체제 커널의 코드이다.

스케줄러는 장기 스케줄러단기 스케줄러가 있다.


장기 스케줄러어떤 프로세스를 준비 큐에 진입시킬지 결정하는 역할로, 프로세스를 메모리에 할당하는 문제에 관여한다.

즉, 시작 상태의 프로세스들 중 어떤 프로세스들을 준비 상태로 만들지 결정하는 역할이다.


단기 스케줄러CPU 스케줄러라고 하는데, 준비 큐에 있는 프로세스들 중 어떤 프로세스들에게 CPU를 할당할지 결정하는 역할로, 시분할 시스템에서 타이머 인터럽트가 발생하면 단기 스케줄러가 호출된다.


단기 스케줄러는 호출되는 빈도수가 잦아 수행 속도가 빠르다.

장기 스케줄러는 호출되는 빈도수가 적어서 상대적으로 느리다.

또한 장기 스케줄러는 메모리에 동시에 올라가 있는 프로세스의 수를 조절하는 역할을 하는데, 현대의 시분할 시스템에서는 장기 스케줄러 없이 곧바로 프로세스를 메모리에 할당한다.

그래서 현대의 시분할 시스템에서는 장기 스케줄러 역할을 중기 스케줄러가 대신한다.


중기 스케줄러는 너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 경우 이를 해결하는 역할로, 너무 많은 프로세스들로 인해 메모리가 부족한 경우에 당장의 CPU가 필요한 프로세스들을 제외한 프로세스들을 메모리에서 제외시켜 디스크의 스왑 영역에 저장한다.

이를 스왑 아웃이라 한다.


중기 스케줄러가 스왑 아웃 시키는 프로세스들 중 0순위는 봉쇄 상태에 있는 프로세스들이다.

그 다음은 준비 상태에 있는 프로세스들이다.

중기 스케줄러로 인해 프로세스의 상태에 추가적으로 중지 상태(suspended, stopped)가 추가되었다.

세부적으로는 봉쇄 상태의 프로세스들이 스왑 아웃되면 중지봉쇄 상태라고 하며, 준비 상태의 프로세스들이 스왑 아웃되면 중지준비 상태라고 한다.

중지봉쇄 상태에서 봉쇄 상태의 프로세스의 인터럽트 작업이 완료되면 중지준비 상태로 바뀐다.

물론, 두 상태 모두 메모리를 조금도 보유하지 않고 디스크에 통째로 스왑 아웃된 상태로 존재한다.






프로세스의 생성



시스템이 부팅된 후 최초의 프로세스는 운영체제가 직접 생성하지만, 그 이후부터는 이미 존재하는 프로세스가 다른 프로세스를 복제 생성하게 된다.

이 때, 프로세스를 생성한 프로세스를 부모 프로세스, 생성된 프로세스는 자식 프로세스라고 한다.

부모 프로세스는 생성한 자식 프로세스들이 모두 종료되고 나서야 종료된다.


프로세스가 수행되려면 자원이 필요한데, 어떤 경우에는 운영체제한테 직접 자원을 할당받을 수 있고 부모 자식 프로세스가 자원을 공유해서 사용할 수 있다.

프로세스 수행 모델부모-자식 프로세스가 공존하며 수행되는 모델과, 자식이 종료(terminate)될 때까지 부모가 기다리는(wait) 모델이 있다.

공존하는 모델은 부모-자식 간의 경쟁 관계가 형셩되며, wait 모델부모 프로세스는 아무 일도 하지 않고 봉쇄 상태에 머물러 있다가, 자식 프로세스가 모두 종료되면 그 때 준비상태가 되어 CPU를 얻을 권한이 생기게 된다.


또한 자식 프로세스는 부모 프로세스와 동일한 주소 공간 즉, 처음 주소 강간을 생성할 때 부모의 주소 공간을 그대로 복사해서 생성한다.

그 후 다른 프로그램을 수행하기 위해 생성된 주소 공간 위에 새로운 프로그램의 주소 공간을 덮어씌워 실행하게 되는 것이다.

예를 들어, fork 시스템 콜로 자식 프로세스를 생성하면 프로세스 ID를 제외한 모든 정보를 그대로 복사한 다음, 자식 프로세스는 exec 시스템 콜을 통해 새로운 프로그램으로 주소 공간을 덮어씌울 수 있다.


프로세스 종료는 두 가지로 나뉜다.

첫 번째는 프로세스가 마지막 명령 수행 후 운영체제에 알려 이루어지는 자발적 종료이다.

프로그램이 마치는 코드 부분에 exit 시스템 콜이 들어가는데, 이를 통해 운영체제에게 자신이 종료됨을 알릴 수 있다.

exit 시스템 콜은 개발자가 명시적으로 호출하지 않더라도 컴파일러에서 자동으로 삽입한다.


두 번째는 비자발적 종료로, 부모 프로세스가 자식 프로세스의 수행을 강제 종료시키는 것이다.

abort 함수를 통해 이루어지며, 강제종료가 발생하는 경우는 1. 자식 프로세스가 할당 자원보다 많은, 과도한 자원을 요구할 때, 2. 자식 프로세스에게 할당된 작업이 필요 없을 때, 3. 부모 프로세스가 종료되었을 때가 있다.

부모 프로세스가 종료되면 운영체제는 자식 프로세스들을 단계적으로 종료시킨다.


만약 어떤 프로세스를 로그아웃 후에도 계속 실행시키고자 한다면, 시스템 프로세스의 자식으로 이양시켜줘야 한다.

즉, 종료되는 프로세스의 자식 프로세스를 계속 실행시키기 위해서 종료되지 않을 다른 프로세스의 자식으로 입양을 보내는 것이다.


프로세스가 자식 프로세스를 생성하는 방법은 fork 시스템 콜을 통해 생성하며, 완전히 부모 프로세스를 복제하는 것이다.

다만, 운영체제에서는 구분하기 위해 식별자 값은 다르게 설정된다.

여기서 복제한다는 것은 부모 프로세스에서 어디까지 명령을 수행했는지까지 등의 정보들이 완전히 똑같이 생성된다는 것이며 놀라운 점은 자식 프로세스는 자신이 복제되었다고 생각하지 않고 원본이라 생각하며 자기를 복제해서 복제본이 생성되었다고 생각한다는 점이다.

구분하는 단서로는 fork 함수의 결과값으로 원본에는 양수를, 복제본에는 0을 준다.


복제를 하고 나서 자식 프로세스에서는 exec 시스템 콜을 통해 새로운 프로그램을 덮어씌워서 첫 부분부터 다시 실행을 시작한다.

부모 프로세스는 wait 함수를 통해 자식 프로세스가 종료되기까지 봉쇄 상태에 머무르도록 하며, 이러한 방식으로 부모-자식 간 동기화가 가능한 것이다.






프로세스 간 협력



운영체제에서 프로세스 간 협력 메커니즘을 지원을 해주는데 대표적으로 IPC(Inter-Process Communication)가 있다.

IPC는 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신을 말한다.

물론, 이러한 통신에서는 의사소통 기능과 동기화를 보장해야 한다.

공유 데이터에 접근하게 된다면 데이터의 불일치가 발생할 수도 있기 때문이다.


IPC의 대표적인 방법으로 메시지 전달 방식공유메모리 방식이 있다.

메시지 전달 방식은 공유 데이터를 사용하지 않고 메시지를 주고받으면서 통신하는 방식으로, 메시지 전달은 특권명령으로 규정하여 커널이 전달해준다.

통신을 원하는 두 프로세스는 커뮤니케이션 링크를 생성한 후 send()와 receive()를 통해 메시지를 주고받는다.


메시지 전달 방식은 또 직접통신간접통신으로 나뉜다.

직접통신은 1대1로 한 쌍의 프로세스에게 링크가 할당되며 대부분 양방향성이다.

간접통신은 메일박스 또는 포트로부터 메시지를 전달받는 것으로, 메일박스를 공유하고 있는 프로세스들과 통신이 가능하며 여러 링크를 가질 수 있다.


공유메모리 방식은 프로세스들이 주소 공간의 일부를 공유한다.

공유메모리 영역은 각자의 프로세스가 그들의 주소 공간 중 일부를 공유하는 곳이므로 여러 프로세스들가 읽고 쓰는 것이 가능하다.

단, 서로 간의 통신을 원할하게 하는 인터페이스를 제공하지만 데이터의 일관성의 문제가 발생할 수 있으며, 이 문제를 커널이 책임지지 않으므로 프로세스들이 직접 동기화 문제를 책임져야 한다.






This post is licensed under CC BY 4.0 by the author.