센로그

3. Processes 본문

CS/운영체제

3. Processes

seeyoun 2023. 9. 13. 14:30

◆ Process

실행중인 프로그램(Program in execution)을 의미함.
프로그램 카운터란?
다음에 실행할 instruction의 주소를 가지고 있는 레지스터

 

ex)

폰 노이만(CPU, Memory)구조 안에서 프로세스를 보자.

 

  • Disk 안에 있는 chrome.exe 프로그램(컴파일된 기계어들이 들어있는 binary file)을 실행하면,
    chrome은 프로세스로써 메인 메모리에 올라감.
  • 메인 메모리의 구조는 보통 byte array(8bit)로 이루어져있으며, byte단위로 address가 붙어있다.
    여기에 chrome이 가지고있던 data와 instruction들이 올라간다.
  • 이때 CPU 캐시는 메모리에 올라온 instruction들의 일부를 캐싱(카피해옴)하고,
    CPU는 캐시로부터 빠르게 instruction에 접근할 수 있다.

 


◆ Process Address Space 

프로세스는 메인 메모리에 특정 구조로 저장된다.

프로세스가 사용하는 메모리 공간은 Text, Data, Stack, Heap구간으로 나뉜다.

  • Text Section : 프로그램 코드(read only)
  • Data Section : global vaiables, static variables...를 저장
  • Stack Section : 함수가 실행되면 Stack Frame(함수의 호출 정보인 파라미터, 리턴 주소, 지역 변수 등이 들어감.)들이 저장되는 공간
  • Heap Section : 동적 할당시 사용되는 공간.
※ Text와 Data는 컴파일 이후 사이즈가 변하지 않음.
반면 Stack과 Heap은 고정된 크기가 아님. 프로그램을 실행하면서 늘어나기도, 줄어들기도 함.
따라서 서로의 영역을 침범(Overflow)하는 일이 발생하기도 함.

 

 

예시) 

 


◆ Process State (프로세스 상태)

프로세스가 실행되는 동안, 프로세스 상태가 변화(state transition)함.

 

  • New: 프로세스가 처음 생성되었을 때의 상태
    → 프로그램이 실행이되면 메모리로 로드가 되고, 초기화를 하고, process identifier(pid)를 부여받음.
    메모리 구조(PCB)도 만들어 주고 실행할 준비가 다 되면 OS가 이를 ready queue에 집어 넣는다(admit).
  • Running: 프로세스가 실행되고 있는 상태
    running 도중 다른 프로세스에 의해 인터럽트가 발생하면, 현재 프로세스는 running 상태에서 ready상태가 된다.
    (나는 실행할 수 있는데, 딴 애 때메 못하는 거니까)
  • Waiting: 프로세스가 I/O나, 이벤트가 발생하기 기다리는 상태
    ex) 현재 프로세스가  running 도중 키보드 입력을 기다리고 있는 동안에 CPU가 놀게 되면 낭비임.
    따라서 현재 프로세스를 waiting 상태로 바꾸고, 그 자리에 ready중인 다른 프로세스를 골라서 run하는 것.
    그러다가 입력이 끝나면, 현재 프로세스는 OS에 인터럽트를 보내서 '입력 다 했어! 이제 다시 실행해도 돼!'를 알려 줌.
    그러면 waiting → ready로 넘어가서 실행을 기다림.
  • Ready: 프로세스가 스케쥴러에 의해 선정되어 프로세서 위에 올라가도록 기다리는 상태.
    즉 프로세스가 언제든 실행될 준비는 됐는데, 안쓰는 프로세서가 없어서 기다리고 있는 상태.
  • Terminated: 프로세스가 종료된 상태

 

ready → running : 스케쥴러가 이 프로세스를 선택해줬을 때.
running → ready : 인터럽트 발생. (CPU를 더 사용할 수 있었는데, 강제로 사용중단된 경우.)
running → waiting : 디바이스나 I/O 같은게 필요해서 더 이상 CPU를 쓸 수 없는 상태. 따라서 양보해주는 경우.

 


Process Control Block (PCB)

프로세스에 관련된 데이터를 OS가 관리하기 위해 사용하는 자료구조

OS는 프로세스마다 PCB를 만들어 관리한다.

PCB에다 Process State, Program Counter, 레지스터 값들, ... 등을 저장해놓음.

  • Process state: 프로세스의 상태.
  • Program counter: 해당 프로세스가 이어서 실행해야 할 명령의 주소를 기록하는 레지스터.
  • CPU registers: 프로세스가 인터럽트 이후 올바르게 작업을 이어가기 위해 참조하는 CPU 레지스터 값. 계산시에 사용하므로, 레지스터 값들은 실행중에 계속 업데이트 된다.
  • CPU-scheduling information: 프로세스의 중요도, 스케쥴링 큐 포인터 등 스케쥴링 파라미터 정보.
  • Memory-management information: base, limit 레지스터 값, 페이지 테이블 등 메모리 시스템 정보.
  • Accounting information: 사용된 CPU 총량, 프로세스 개수, 시간 제한 등.
  • I/O status information: 프로세스에 할당된 입출력 장치 목록, 열린 파일 목록 등.

 

※ 참고
메인 메모리 위에 커널과 프로세스들이 다 올라가 있다고 했는데, PCB는 커널에 속하는 데이터임. 
아무나 접근 못 함.

 


◆ Process Scheduler

프로세스 스케쥴러는 주어진 코어에 어떤 프로세스를 실행할지 결정해주는 역할을 한다.

 

CPU는 한번에 하나의 프로세스만 수행하기 때문에, 스케쥴링을 통해 CPU를 최대한 효율적으로 활용할 수 있도록 하는 게 목표이다.

 

 

 

프로세서를 기다리고 있는 프로세스들이 많을 것임

이런 기다리는 프로세스들을 queue로 관리하며, 스케쥴링 알고리즘에 따라 관리됨.(관리 알고리즘 존재)

  • Ready queue : 프로세서 할당을 받으면 언제든지 실행될 준비가 된 프로세스들을 관리하는 큐
  • Wait queue : 이벤트나 I/O를 기다리고 있는 프로세스들을 관리하는 큐
    - 상황에 따른 wait queue가 따로 존재함.
    I/O, event, children, interrupt, ..를 기다리는 wait queue가 따로 존재해서 상황에 맞게 관리가 됨.
    - waiting이 끝나면 ready queue로 다시 돌아옴.

 

예시) 

 


◆ Context Switch

CPU가 어떤 프로세스를 실행하고 있다가, 다른 프로세스로 넘어가는 것을 Context Switch(문맥 교환)이라고 함.

Context에는 프로그램 카운터 값 + 레지스터 값을 담고있다.

Context Switch는 말 그대로 Context를 교체하 것이다.

 

 

그림을 보자.

P0를 실행하고 있다가, P1가 스케쥴링되어 실행되는 상황이다.

 

(타이머 인터럽트에 의해)  프로세스 P0는 유저 모드 → 커널 모드로 변경하고,
P0의 프로그램 카운터값과 레지스터 값을 백업한다. (Save State)

P1의 프로그램 카운터값과 레지스터 값을 가져온 후 (Load State) ,
유저 모드로 복귀하여 P1을 실행한다. 

 

 

이 과정을 Context Switching이라고 부름!

 

 

  • Context switch 시간은 pure overhead, 즉 관리를 위해 추가적으로 드는 필수 코스트이다.
    OS와 PCB가 복잡할 수록 context switch 시간이 오래걸린다.
  • Context switch 하는 동안에는 OS가 CPU를 점유하기에 프로세스 실행을 못하므로, 이를 효율적로 수행해야 낭비되는 시간을 줄일 수 있을 것!

 

※ 프로세스가 실행중일 때는 PCB의 PC값, 레지스터 값들이 업데이트가 안된다!
Context Switching 할 때에 빼내서 저장한다.

즉, 실행하는 중에는 PC값, 레지스터 값이 항상 최신값인 건 아니다!

 


Operations on Process

시스템은 프로세스 생성 및 종료에 관한 메커니즘을 제공해야 한다.

  • process creation
  • process termination

 


Operations on Process - Process Creation

프로세스 사이에도 부모 - 자식이란 관계가 형성되어 있다.

보통 부모 프로세스로부터 많은 자식 프로세스가 뻗어나가는 트리 구조를 이룬다. (Process Tree)

각각의 프로세스가 process identifier(pid)를 가지고 있어서, 이를 통해 구별되고 관리된다.

 

부모-자식간 어떤 식으로 동작할지에 대한 옵션은 OS마다 다르다.

이 옵션으로는 자원 공유 옵션(자식과 부모가 자원을 어느정도로 공유할 것인지), 실행 옵션(자식과 부모가 같이 도는지, 부모가 자식의 실행을 기다야 하는지, ..) 등이 있다.

 

 

ex) 

UNIX에는 프로세스를 만들기 위한 system call function(시스템 콜 함수)이 존재한다.

예를들어 부모 프로세스가 시스템 콜 함수인 fork()를 통해 자식 프로세스를 만들면, 부모의 코드들이 자식에게 복사된다.

이때 부모와 자식은 fork()의 반환값을 통 구별할 수 있다. (분기별 실행)

  • fork() < 0이면 프로세스 생성 실패
  • fork() == 0 이면 자식 프로세스
  • fork() > 0이면 부모 프로세스

 

 

 

코드를 보자.

자식 프로세스를 생성하고 복제(fork()) 이후,

자식 프로세스는 exec()을 통해 (기존에 할당받았던) 메모리를 덮어쓴다.

그동안 부모 프로세스는 자식 프로세스의 실행이 종료되기를 기다린다(wait()). 

 
fork()는 부모 프로세스의 메모리 공간을 복사해서 자식 프로세스에게 새로운 메모리를 할당해주는 반면,
exec()는 현재 프로그램의 메모리 영역에 exec의 인자로 전달된 프로그램의 메모리로 덮어 씌워버리는 함수이다.

 

 

프로세스 상태 측면에서 보자.

부모가 자식 프로세스의 실행을 기다리고 있는 waiting 상태라 하자.

자식 프로세스는 실행이 끝나면 running 상태 → terminated 상태로 갈 것

그러면 parent는 다시 ready 상태로 갈 수 있음!

 


◆ Operations on Process - Process Termination

프로세스는 보통 main에서 return 하거나, 시스템 콜 함수인 exit() 를 호출하면 Terminated 상태로 전환됨.

프로세스는 종료 될 때 마지막 문장의 실행을 끝내고, exit()을 사용하여 운영체제에게 자신의 삭제를 요청하면서 종료된다. 

이때 프로세스는 자신의 부모가 호출한 wait() 시스템 호출을 통해서 상태 값을 반환하며, 

물리 메모리/가상 메모리/열린 파일/입출력 버퍼를 포함한 프로세스의 모든 자원이 운영체제로 반납(deallocate)된다.

(단, 프로세스의 종료 상태가 저장되는 프로세스 테이블의 해당 항목은 부모 프로세스가 wait()을 호출할 때까지 남아있게 된다)

 

※ 부모 프로세스는 wait() 시스템 콜 함수를 사용하여 자식 프로세스가 종료할 때까지 기다릴 수 있다고 했다.
이때 부모가 자식의 종료 상태를 얻어 낼 수 있도록 하는 하나의 파라미터를 전달 받는다.
이 시스템 호출은 부모가 어떤 자식이 종료되었는지 구별할 수 있도록 종료된 자식의 pid를 반환한다.

 

※ exit()와 abort()

- exit() : 정상 종료
- abort() : 비정상 종료
parent가 어떤 이유(child가 리소스를 너무 많이 쓰는 등)로 인해 강제로 child를 종료시키는 시스템 콜 함수이다.

 

※ Cascading Termination
어떤 프로세스가 종료하게 되면, 하위에 있는 모든 자식 프로세스는 종료되어야 함을 의미한다.

보통은 자식 프로세스 → 부모 프로세스 순서로 차례대로 종료되는 것이 바람직하다.

<프로세스의 바람직한 종료>
부모 프로세스가 wait()하고 있는 상황에서 자식 프로세스가 종료되는 상황이 바람직하다.

<프로세스의 잘못된 종료>
zombie process :
- 자식 프로세스가 종료 되었지만 부모 프로세스가 아직 wait() 호출을 하지 않은 경우, 자식 프로세스를 좀비 (zombie) 프로세스라고 한다.
- 모든 프로세스는 종료하게 되면, 좀비 상태가 되지만 아주 짧은 시간 동안 머무르게 되고, 부모가 wait()를 호출하면 좀비 프로세스의 pid 및 프로세스 종료 상태가 저장되는 프로세스 테이블의 해당 항목이 운영체제에게 반환된다.
ㆍorphan process :
- 부모 프로세스가 자식 프로세스보다 먼저 종료된 경우, 남은 자식 프로세스를 고아(orphan) 프로세스라고 한다.
(자식 프로세스는 종료될 때 리소스를 반납하고 부모의 wait()에다가 보고를 해야한다. 그런데 wait()을 호출해줄 부모가 사라진 것!!)
- 이런 경우 init process를 새로 지정해주어서 핸들링하도록 한다.

 


Inter-Process Communication (IPC)

프로세스 간 협력 메커니즘

기본적으로 프로세스는 독립적이고 서로 간섭하지 않지만,

경우에 따라서는 서로 협력(ex: 프로세스 간 데이터나 리소스 공유)이 필요할 때가 있다. 

이때 사용되는 프로세스 간 협력 메커니즘에 대해 알아보자.

 

 

다음 두 가지 종류의 메커니즘이 있다.

  • Shared memory
    : 메모리 공간을 공유하는 방법
  • Message passing
    : 메세지를 전달하는 방법

 

이들에 대해서 살펴보자.

 


◆ IPC - Shared Memory

공유하는 메모리 공간을 두는 방식

일반적으로 프로세스 간 메모리는 독립적으로 보호를 받음.

그러나 데이터를 공유할거면, 공유할 공간이 필요할 것임.

따라서 프로세스 A와 B 사이에 공유하는 메모리 공간을 두고, 거기에다 공유할 정보를 넣어 처리하는 방법

 

장단점

  • 단점
    - 개발자가 동기화 문제를 고려해야 한다.
    즉, 하나의 메모리를 여러 프로세스가 사용하는 것이므로, 프로세스 A가 쓴 공간을 B가 덮어버리는 문제가 있을 수 있다. → 프로세스가 데이터 쓰는 순서(우선권)를 부여하는 등 synchronization 과정이 필요함~
    - 여러 명이 접근하다 보면 누가 수정했는지 모를 수 있다.
  • 장점
    - 커널의 개입 횟수가 적으니 비교적 빠르다.

 

※  producer-consumer 문제

개요 : 
생산자-소비자 문제는 Shared Memory 방식으로 협력하는 경우에서, 두 프로세스가 동시에 동작할 때 일어날 수 있는 이슈를 말한다.

협력하는 프로세스 중 정보를 생산하는 프로세스를 producer, 정보를 소비하는 프로세스를 consumer라고 한다. producer는 아이템을 계속 생산하고, consumer는 생산된 아이템을 계속 소비한다고 가정하자. 

보통 정보가 생산되는 속도가 소비하는 속도보다 빠르기 때문에 동기화 문제가 발생할 수 있다.
→ 이를 해결하기 위해 생산된 데이터를 담아두는 버퍼(Buffer)를 사용한다.

방법 :
버퍼의 시작점(비어있는 첫 인덱스), 끝점(차있는 첫 인덱스)을 표현하는 in, out 변수를 만들어 서로 공유하도록 한다. customer는 이를 통해 이 버퍼에 데이터가 있는지 없는지 판단할 수 있다. (in == out 인지 체크)


작동 예시 : 
1) 버퍼가 비어있을 때 in, out은 같은 공간을 가리킴.
이 경우 consumer은 갖고갈 정보가 없으므로, 버퍼가 찰 때까지 기다림.


2) producer가 아이템을 생산하면, 아이템이 버퍼에 들어가고, 이때 in은 다음 위치를 가리키도록 바뀜.


이를 통해 consumer는 아이템이 있는 것을 확인하고 아이템을 가져와 소비함


3) consumer가 item을 소비하면 out도 다음 위치로 바뀌어서 in과 같은 공간을 가리킴.
다시 consumer은 갖고갈 정보가 없으므로, 버퍼가 찰 때까지 기다림

 

※ POSIX로 Shared memory 만드는 예시 코드

 


◆ IPC - Message passing 

공유할 데이터를 담은 메세지 큐커널이 관리해주는 방식.

커널이 메세지 큐를 관리해줌. 메세지 큐에다가 공유할 정보를 집어넣고, 꺼내쓰며 공유하는 방식.

커널 안에 메일 박스가 있다고 생각하면 됨. 프로세스가 편지같은 걸 남겨놓는 느낌.

 

협력할 프로세스들은 서로 간의 communication link를 설립한 후,

message passing에 필요한 operation을 사용해 데이터를 공유한다.

 

다음 두 operation이 존재한다.

  • send(message)
  • receive(message)

 

장단점

  • 단점
    - 커널을 통해서 메세지를 주고 받기 때문에 비교적 오버헤드가 크다.
  • 장점
    - 대신 개발자가 동기화 문제를 고려하지 않아도 된다.
    - 메시지 형태이기 때문에 누가 보냈는지 다 알 수 있다.

 

'CS > 운영체제' 카테고리의 다른 글

6. Synchronization Tools  (0) 2023.10.14
5. CPU Scheduling  (0) 2023.09.20
4. Therad & Concurrency  (0) 2023.09.18
2. Operating System Structures  (0) 2023.09.06
1. OS overview  (0) 2023.09.04
Comments