프로세스 관리

불불이·2021년 3월 2일
0

프로세스의 개념

프로세스

실행중인 프로그램

프로세스를 이해하기 위해서는 프로세스의 문맥(context)에 대해 알 필요가 있다.

프로세스 문맥(context) = 프로세스의 모든 정보

프로세스가 현재 어떤 상태에서 수행되고 있는지 정확히 규명하기 위해 필요한 정보를 의미한다.

CPU의 독점들 막기 위해서 여러 프로세스가 함께 수행되는 시분할 시스템 환경에서는 타이머 인터럽트에 의해 짧은 시간동안 CPU를 빼앗겼다그 추후 CPU를 획득하는 식으로 관리가 이루어진다. 따라서 우리는 어느 부분까지 명령을 수행했는지 직전 수행 시점의 정확한 상태를 재현할 필요가 있다.

이때 정확한 재현을 위해 필요한 정보가 프로세스의 문맥이다.

프로세스의 문맥안에는

  • 하프드웨어 문맥

    CPU의 수행상태 프로그램 카운터가보고 각종 레지스터에 저장하고 있은 것들

  • 프로세스의 주소공간

    코드, 데이터, 스택으로 구성되어있는 자기 자신만의 독자적인 주소 공간을 가지고 있다.

  • 커널상의 문맥

    PCB와 커널스택


프로세스간의 상태

실행상태

프로세스가 CPU를 보유하고 기계어 명령어를 실행하고 있는 상태를 가리킨다.

준비상태

프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있지만 CPU를 할당받지 못한 상태를 가르킨다.

봉쇄상태

CPU를 할당받더라도 당장 명령을 실행할 수 없는 프로세스의 상태

시작(new)상태

프로세스가 시작되어 그 프로세스를 위한 각종 자료구조는 생성되었지만 아직 메모리획득을 승인받지 못한 상태

완료상태(terminated)

프로세스는 종료되었으나 운영체제가 그 프로세스와 관련된 자료구조를 완전히 정리하지 못한 상태를 말한다

  1. 프로세스a 실행중, 타이머 인터럽트가 발생 / CPU의 제어권→ 운영체제
  2. 운영체제는 타이머 인터럽트 처리루틴으로 가서 수행 중이던 프로세스의 문맥을 저장 (문맥교환)
  3. 준비상태에 있는 프로세스 중에서 새롭게 CPU의 제어권을 부여할 프로세스를 선택한다. (디스패치)
  4. 원래 수행중이던 프로세스A는 준비상태로 변하고 새롭게 CPU를 할당받은 프로세스가 실행 상태가 된다.

문맥교환(Context-Switch)

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

문맥교환이 일어나는 경우

  1. 타이머 인터럽트가 발생하는 경우
  2. 실행상태에 있던 프로세스가 입출력 요청으로 봉쇄상태로 바뀌는 경우

디스패치(dispatch)

준비상태에 있는 프로세스들 중에서 CPU를 할당받을 프로세스를 선택한 후 실제로 CPU의 제어권을 넘겨받는 과정을 CPU 디스패치라고 한다.

입출력이 완료될 때까지 CPU를 반환한 다음 디스크 입출력 서비스를 기다리며 봉쇄 상태로 바뀌게 된다. 그러면 CPU를 기다리는 준비상태의 프로세스들 중에서 CPU스케줄러가 적절한 프로세스를 하나 선정해 CPU를 할당하게 된다. 준비 상태의 프로세스는 CPU만 획득하면 곧바로 명령을 수행할 수 있으므로 이번에 CPU를 할당받은 프로세스는 실행 상태로 변경되어 자신의 코드를 CPU에서 실행하게 된다.

그렇다면 디스크 입출력을 요청한 프로세스는 그 후 어떠한 상태 변화를 겪게 되는 것일까?

  1. 입출력을 요청한 프로세스A는 디스크 입출력을 기다리는 큐에 줄 서 있는다.

  2. 자기 차례가 되어 디스크 컨트롤러부터 서비스를 받는다.

  3. 디스크 컨트롤러가 CPU에게 인터럽트를 발생키셔 입출력이 완료되었다는 사실을 알린다.

  4. CPU는 프로세스B를 실행하고 있다가 인터럽트가 발생한 것을 확인하고 그에 대응하는 루틴을 수행한다.

  5. 이 루틴이 진행되는 동안 CPU에서 수행되던 프로세스B의 상태는 사용자모드 실행상태에서 커널모드 실행상태로 바뀐다.

    (비록 인터럽트 처리루틴이 직전에 실행중이던 프로세스와는 무관한 업무를 담고 있기는 하지만 인터럽트 처리를 우리는 편의상 직전 프로세스의 문맥에서 실행된 것으로 간주한다. 따라서 인터럽트가 발생한 원인과 관계없이 인터럽트를 당한 프로세스가 사용자 모드에서 실행되다가 커널모드로 진입한 것으로 간주하게 된다.)

  6. 프로세스A는 봉쇄상태에서 준비상태로 바꾼 후 장치의 로컬버퍼에 있는 내용을 메모리로 이동시켜 일련의 업무를 수행한다.


프로세스 제어블록(PCB)

운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담 는 커널 내의 자료구조 구조를 뜻한다.

PCB는 다음과 같은 요소들로 구성되어 있다.

  • 프로세스 상태: CPU 할당 여부
  • 프로그램 카운터(PC)
  • CPU 레지스터: CPU 연산을 위해 현 시점에 레지스터에 어떤 값을 저장하고 있는지
  • CPU 스케줄링 정보: CPU 스케줄링
  • 메모리 관리 정보: CPU 메모리
  • 자원 사용 정보
  • 입출력 상태 정보

문맥 교환(Context-Switch)

하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU의 제어권이 이양되는 과정을 뜻한다.

  1. 사용자 프로세스가 CPU를 할당받고 실행되던 중에 타이머 인터럽트가 발생하면 CPU의 제어권은 운영체제에게 넘어가게 된다.
  2. 운영체제 타이머 인터럽트 처리루틴으로 가서 직전까지 수행 중이던 프로세스의 문맥을 저장하고 새롭게 실행시킬 프로세스에게 CPU를 이양한다.
  3. 원래 수행중이던 프로세스는 준비상태로 변경, 새롭게 CPU를 할당받은 프로세스는 실행상태
  4. 문맥교환 중에 원래 CPU를 보유하고 있던 프로세스는 프로그램 카운터 값 등 프로세스의 문맥을 자신의 PCB에 저장하고 새롭게 CPU를 할당받을 프로세스는 예전에 저장했던 자신의 문맥을 PCB로부터 실제 하드웨어로 복원시키는 과정을 거친다.

문맥교환이 일어나지 않는 경우

프로세스 실행상태일 때 시스템 콜이나 인터럽트가 발생하면 CPU의 제어권이 운영체제로 넘어와 원래 실행중이던 프로세스의 업무를 잠시 멈추고 운영체제 커널의 코드가 실행된다. 이 경우에도 CPU의 실행 위치 등 프로세스의 문맥 중 일부를 PCB에 저장하게 되지만 이러한 과정을 문맥교환이라고 하지 않는다. 이는 하나의 프로세스의 실행모드만이 사용자모드에서 커널모드로 변경되는 것일 뿐, CPU를 점유하는 프로세사가 다른 사용자 프로세스로 변경되는 과정이 아니기 때문이다. 이와같은 모드 변경에 비해 문맥교환에는 훨씬 많은 오버헤드가 뒤따르게 된다.

  • 타이머 인터럽트
  • 프로세스 입출력 요청 시스템 콜 → 봉쇄 상태에 들어가는 경우

그 밖의 인터럽트나 시스템 콜 발생 시에는 문맥교환이 일어나지 않고 실행 모드만이 변경될 뿐이다.

문맥교환에 소요되는 시간은 시스템 입장에서 볼 때 일종의 오버헤드라고 할 수 있다. 따라서 타이머에게 CPU 할당시간을 아주 작게 세팅해 프로세스 간 문맥 교환이 빈번하게 발생하도록 하면 오버헤드가 상당히 커지고, 반대로 CPU 할당시간을 너무 크게 설정하면 시분할 시스템의 의미가 퇴색하게 되므로 적절한 CPU 할당시간을 정하는 것이 중요하다.


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

운영체제는 준비 상태에 있는 프로세스들을 줄 세우기 위해 준비큐를 두고 준비 큐의 제일 앞에 줄 서 있는 프로세스에 제일 먼저 CPU를 할당한다. 준비큐에 프로세스를 줄 세우는 방법은 CPU 스케줄링 방법에 다라 달라진다.

장치큐

CPU를 기다리는 프로세스를 줄 세우는 준비 큐 외에도 운영체제는 특정 자원을 기다리는 프로세스들을 줄 세우기 위해 자원별로 장치 큐(device queue)를 둔다.

ex) 디스크 입출력 큐, 키보드 입출력 큐

특히 공유데이터라는 일종의 소프트 웨어 자원에서는 일관성을 훼손하지 않게 하나의 한 프로세스만 사용할 수 있다.

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

각 프로세스가 CPU를 기다리는지, 입출력을 기다리는지 등의 정보를 커널이 총체적으로 관리한다는 뜻이다. 예를 들어 타이머 인터럽트가 발생하면 커널은 자신의 데이터 영역에 있는 준비 큐의 정보를 참조해 다음에 어느 프로세스에게 CPU를 할당할지 결정하고, 현재 실행 중인 프로세스는 준비 큐의 제일 뒤로 보낸다.

작업큐

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

  • 그래서 작업 큐에 있다고 반드시 메모리를 가지고 있는 것은 아니다.
  • 준비큐에 속한 프로세스들은 준비상태에 장치 큐에 속한 프로세스들은 봉쇄상태에•••
  • 작업큐가 가장 넓은 개념이고 준비큐와 장치큐에 있는 프로세스들은 모두 작업큐에 속한다.

준비큐


스케줄러

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

장기 스케줄러(long term scheduler) = 작업 스케줄러

어떤 프로세스를 준비 큐에 진입시킬지 결정하는 역할을 한다.

  • 준비 큐는 CPU만 얻으면 당장 실행할 수 있는 프로세스의 집합이고 CPU에서 실행되기 위해서는 프로세스가 메모리를 보유해야 하므로 장기 스케줄러는 프로세스에게 메모리를 할당하는 문제에 관여하게 된다.
  • 시작상태에서 어떤 프로세스를 준비상태로 할지 경정하는 역할
  • 수십초 내지 수분 단위로 가끔 호출되기 때문에 상대적으로 속도가 느린 것이 허용된다.
  • 메모리에 동시에 올라가있는 프로세스의 수를 조절하는 역할을 한다.(메모리 할당 여부)
  • 그러나 현대의 시분할 시스템에서 사용되는 운영체제에는 일반적으로 장기 스케줄러를 두지 않는 경우가 대부분이다.
  • 현대에는 바로 메모리를 할당해 준비큐에 넣어주게 된고, 중기 스케줄러를 사용한다! 헐

단기 스케줄러(short term scheduler)

준비 큐에 있는 어떠한 프로세스에게 CPU를 할당할 것인가를 단기 스케줄러가 결정하게 된다.

  • 시분할 시스템에서는 타이머 인터럽트가 발생하면 단기 스케줄러가 호출된다.
  • 밀리초 정도의 시간 단위로 매우 빈번하게 호출되기 때문에 수행속도가 빨라야한다.

중기 스케줄러(medium term scheduling)

너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 경우 이를 해결하기 위해 메모리에 적재된 프로세스의 수를 동적으로 조절하기 위해 추가된 스케줄러이다.

  • 프로세스당 보유 메모리양이 지나치게 적어진 경우 이를 완화시키기 위해 일부 프로세스를 메모리에 디스크로 스왑 아웃 시키는 역할을 한다.

스왑 아웃

스왑 아웃시켜야 하는 경우 0순위인 프로세스는 봉쇄 상태에 있는 프로세스들이다.

그래도 부족한 경우는 타이머 인터럽트가 발생해 준비 큐로 이동하는 프로세스를 추가적으로 스왑 아웃 시킨다.

  • 장기 스케줄러와 마찬가지로 메모리에 올라가있는 프로세스의 수를 조절하는 역할을 수행한다.
  • 중기 스케줄러의 등장으로 인해 스케줄러의 중지 상태가 추가된다.

중지 상태

외부적인 이유로 프로세스의 수행이 정지된 상태를 나타내는 중지상태

중지상태에 있는 프로세스는 외부에셔 재개시키지 않는 이상 다시 활성화 될 수 없으므로 메모리 자원이 당장 필요하지 않다. 따라서 중지 상태의 프로세스는 메모리를 통째로 빼앗기고 디스크로 스왑 아웃 된다.

디스크로 스왑 아웃 된 프로세스의 상태가 대표적인 중지 상태의 예라고 할 수 있다.

중지준비 상태(suspended ready)

준비상태 있던 (타이머 인터럽트) 프로세스가 중기 스케줄러에 의해 디스크로 스왑 아웃 되면 이 프로세스의 상태는 중지 준비상태가 된다.

중지봉쇄 상태(suspended block)

봉쇄 상태(block) 있던(입출력 기다리는..) 프로세스가 중기 스케줄러에 의해 스왑 아웃 되면 이 프로세스의 상태는 중지봉쇄상태가 된다.

중지 봉쇄상태이던 프로레스가 봉쇄되었던 조건을 만족하게 되면 이 프로세스의 상태는 중지준비 상태로 바뀐다. 둘다 메모리를 조금도 보유하지 않았다.


프로세스의 생성

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

부모프로세스

프로세스를 생성한 프로세스

자식프로세스

새롭게 생성된 프로세스를 자식 프로세스라 한다.

  • 프로세스의 세계에서는 자식이 먼저 죽고, 이에 대한 처리는 자식을 생성했던 부모 프로세스가 담당하는 방식으로 진행된다.
  • 자식을 여러 단계에서 만든 프로세스는 그 프로세스가 생성했던 모든 후손 프로세스들을 연쇄적으로 종료시킨 후에야 본인이 종료될 수 있다.

생성된 프로세스가 작업을 수행하기 위해 자원을 얻는 방법

(운영체제 및 자원에 종류에 따라 다름)

  1. 운영체제로부터 직접 자원을 할당받는 경우
  2. 부모 프로세스와 같은 자원을 공유해서 사용하는 경우

프로세스가 수행되는 모델

  1. 부모와 자식이 공존하며 수행되는 모델

    자식과 부모와 같이 CPU를 획득하기 위해 경쟁하는 관계

  2. 자식이 종료(terminate)될 때까지 부모가 기다리는(wait)모델

    자식 프로세스가 종료될 때 까지 부모 프로세스는 아무 일도 하지 않고 봉쇄 상태에 머물러 있다가, 자식 프로세스가 종료되면 그때 부모 프로세스가 준비상태가 되어 다시 CPU를 얻을 권한이 생기게 된다.

프로세스가 생성되면 자신만의 독자적인 주소공간을 갖게 된다. 부모 프로세스가 자식 프로세스를 생성하면 자식 프로세스는 부모 프로세스와는 별도로 주소 공간을 가지게 되는데, 처음 주소공간을 생성할 때에는 부모 프로세스의 주소 공간 내용을 그대로 복사해서 생성한다. 자식 프로세스가 다른 프로그램을 수행하기 위해서는 생성된 주소 공간 위에 새로운 프로그램 주소공간을 덮어 씌어 실행하게 되는 것이다.

프로세스의 생성 절차에 대해 유닉스의 예

  1. 유닉스에서는 fork() 시스템 콜을 통해 새로운 프로세스를 생성할 수 있다.

Fork()시스템 콜

자식 프로세스를 생성할 때 부모 프로세스의 내용을 그대로 복제 생성하게 된다.

즉 프로세스 ID를 제외한 모든 정보(운영체제 커널 내의 정보와 주소공간의 정보)를 그대로 복사하는 방법을 사용한다. 따라서 부모 프로세스와 자식 프로세스는 비록 주소공간을 따로 갖게 되지만 주소 공간 내에는 동일한 내용을 갖게 된다.

  1. exec() 시스템 콜을 통해 새로운 프로그램으로 주소공간을 덮어씌울 수 있다.

프로세스의 종료

위에서 언급했지만 원칙적으로 후손 자식들이 모두 종료되어야 부모 프로세스가 종료될 수 있다. 이와 관련해 프로세스의 종류는 두가지로 나뉜다.

  1. exit()

    프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려 이루어지는 자발적 종료이다. 프로세스는 명령을 모두 수행 한 후, 프로그램이 마쳐지는 코드 부분에 exit()라는 시스템 콜을 넣어주도록 되어 있다.

  2. abort()

    비자발적 종료로 부모 프로세스가 자식 프로세스의 수행을 강제로 종료시키는 것이다. 이는 abort()라는 함수를 통해 이루어지게 된다. 강제 종료가 발생하는 경우는 다음과 같이 나뉠 수 있다.

    • 자식 프로세스가 할당 자원의 한계치를 넘어서는 많은 양의 자원을 요구할 때
    • 자식 프로세스에게 할당된 작업이 더 이상 필요하지 않을 때
    • 부모프로세스가 종료되는 경우

    특히 부모프로세스가 종료되는 경우 운영체제는 자식 프로세스가 더 이상 수행되지 못하게 하기 때문에 단계적인 종료가 발생한다.

다른 프로세스에게 자식을 이양시키는 경우

사용자 계정으로 서버 컴퓨터에 접속해서 수행시킨 프로그램을 로그아웃 후에도 계속 수행시켜야 하는 경우가 있을 수 있다. 이 경우 로그아웃을 하게 되면 로그인 창 아래에 생성된 모든 자식 프로세스들이 종료되기 때문에 이러한 프로세스를 계속 실행시키고 싶으면 해당 프로세스를 로그아웃 후에도 존재하는 시스템 프로세스의 자식으로 이양시키는 절차가 필요하다. 즉 종료되는 프로세스의 자식 프로세스를 계속 실행시키기 위해서 종료되지 않을 다른 프로세스의 양자로 자식 프로세스를 보내어 기존 부모 프로세스가 종료된 후에도 다른 프로세스 아래에서 계속 수행될 수 있도록 한다.

프로세스가 자식 프로세스를 생성하는 방법

  1. 운영체제는 fork() 시스템 콜을 제공한다.
  2. 프로세스가 fork() 시스템 콜을 하게 되면 CPU의 제어권이 커널로 넘어가게 되고
  3. 커널은 fork()를 호출한 프로세스를 복제해 자식 프로세스를 생성
  4. 부모 프로세스와 똑같은 문맥을 갖게된다. (PC 프로그램카운터 어디까지 명령을 실행했는지)
  5. 즉 부모 프로세스의 처음부터 수행을 시작하는 것이 아니고 부모 프로세스가 현재 수행한 시점(프로그램 카운터)부터 수행하게 된다.

인간과 비교하자면 똑같은 자식을 낳는거지만 부모의 기억 모든 과거를 다 기억하는 똑같은 복제인간 하나를 만드는 것이고 복제된 인간 즉 자식 프로세스는 자기가 복제된 프로세스라는 것 까지 표시된다.

그것은 fork() 함수의 결괏값으로 원본에게는 양수를 주고 복제본에게는 0을 준다는 점이다. (exec())

(조건문을 사용해 원본 프로세스와 복제본 프로세스가 다른 작업을 하도록 프로그램을 작성할 수 있다.)

다른 작업을 할 수 있는 이유는 조건문때문이지만 두 프로세스 모두 동일한 코드를 가지고 있어 자식 프로세스에게 부모와는 다른 독자적인 프로그램을 수행시킬 수 있는 메커니즘이 필요하다. ⇒ exec()

자식 프로세스와 부모 프로세스의 동기화

fork(), exec()등은 특권 명령이다. 이것 외에도 wait()시스템콜도 있는데 자식 프로세스가 종료되기를 기다리며 부모프로세스가 봉쇄상태에 머무르도록 할 때 사용된다. fork()후에 wait()를 호출하면 커널은 자식 프로세스가 종료될 떄 까지 봉쇄상태에 머무르고 자식 프로세스가 종료되면 부모를 준비상태로 변경하여 작업을 재개시킬 수 있다. 부모프로세스는 자식 프로세스가 종료되길 기다리며 수면상태에 머무른다.


프로세스 간의 협력

프로세스는 각자 자신만의 독립적인 주소 공간을 가지고 수행되며 프로세스가 다른 프로세스의 주소 공간을 참조하는 것은 허용되지 않는다.

그럼 다른 프로세스와 정보를 주고받을 수 있는 방법은?

  • 왜? 경우에 따라서는 독립적인 프로세스들이 협력할 때 업무의 효율성이 증진될 수 있다.
  • 운영체제는 프로세스 간의 협력 메커니즘을 제공해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있게 한다.

IPC(Inter-Process Communication)

하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스간에 발생하는 통신과 동기화를 이루기 위한 메커니즘

  • 의사소통 기능
  • 동기화 기능

IPC의 대표적인 방법으로는 메시지 전달과 공유 메모리방식이 있는데 이 두 방식의 차이는 프로세스 사이에 공유데이터를 사용하는가, 그렇지 않은가에 있다.

메시지 전달 방식

프로세스 간에 공유데이터를 일체 사용하지 않고 메시지를 주고받으며 통신하는 방식

이때 두 프로세스의 주소 공간이 다르므로 메시지 전달을 직접할 수는 없으며 커널이 그 역할을 하게 된다.

메시지 통신을 하는 시스템은 커널에 의해 send, receive라는 두가지 연산을 제공받게 되고 ,이 두 연산을 통해 프로세스는 전달할 메시지를 운영체제 시스템 콜 방식으로 요청한다.(특권명령)

  1. 커뮤니케이션 링크를 생성(물리적 방법, 논리적 방법 존재)
  2. send(), recevie()를 이용해 메시지를 주고받게된다.(직접통신, 간접통신)
  • 메시지의 전송 대상이 다른 프로세스인지 아니면 메일박스라는 일종의 저장공간인지에 따라 나뉨

  • 메일박스를 공유하기 때문에 어떤 프로세스가 받았는지 모름 그래서 그 안에 따로 링크를 생성한다.

공유메모리 방식

프로세스들이 주소 공간의 일부를 공유한다.

각자의 주소 공간에 공통적으로 포함되는 영역으로 여러 프로세스가 읽고 쓰는 것이 가능하다. 실제로는 a와 b가 독자적인 주소 공간을 갖고 있지만 물리적 메모리에 매핑될 때 공유 메모리 주소 영역에 대해서는 같은 주소로 매핑된다.

  • 일관성 문제가 유발될 수 있다.
  • 커널이 책임지지 않고 프로세스들이 책임져야한다 → 아마 언젠간 설명하지 않을까..
profile
https://nibble2.tistory.com/ 둘 중에 어떤 플랫폼을 써야할지 아직도 고민중인 사람

0개의 댓글