[운영체제] Ch3. Processes

nothingisme·2023년 9월 24일

[ 운영체제 ]

목록 보기
1/1
post-thumbnail

1️⃣ Process


  • 정의 : 실행중인 프로그램

    • 프로그램 : passive entity, 실행하지 않은 상태의 실행 파일(instruction들)
    • 프로세스 : active entity, 실행 요청해서 실행중인 프로그램
  • 실행중 → 프로그램 카운터(pc)가 다음 instruction과 resource에 대한 정보를 갖고 있다.

    • 프로그램 카운터 : 진행 상황 기록하는 역할. 다음에 어떤 instruction인지 저장한다.
    • 리소스 : 실제 프로그램이 돌아가는 중에 사용중인 파일, open files 등
  • 프로세스 과정 그림

    • Disk
      • Program = binary file with machine instructions
    • Main Memory
      • Program Code : 프로그램 → 프로세스가 되려면 CPU가 읽어서 처리할 수 있도록 프로그램 코드가 메인 메모리에 올라가 있어야 한다.
      • Byte Array : 메인 메모리에서는 Byte Array 방식으로 프로그램 코드가 저장되어 있다. → 바이트마다 주소가 붙어있다. 바이트 단위로 주소를 참조. 각 주소마다 8비트(= 1byte)의 데이터 저장
    • CPU
      • Cache : 메인 메모리(addr)에 있는 데이터를 미리 cache에 copy 해둔다.
      • Registers : 워드(word)라는 단위(보통 2바이트 = 16bits)로 읽어와서 임시로 저장한다.

2️⃣ Process in Memory


  • 메모리에는 하드웨어 instruction 뿐만 아니라 다른 것들도 올라간다

< 고정된 크기 >

  • Text : 프로그램 코드. read-only
    • binary. 제일 아래 부분. 프로그램을 실행하면서 바뀌지 않는 부분 .코드는 한 번 컴파일하면 바뀌지 않음. 다시 컴파일 하지 않는 이상 read-only. → 프로세스를 실행중인데 프로그램이 바뀌면 안 되니까 당연히 read-only 로 보호되어야 한다.
  • Data : 전역 변수

< 고정된 크기 X >

  • Stack : 지역 변수, parameter, return address of function
    • 지역 변수
    • 함수를 호출 했을 때 parameter
    • 함수의 반환 주소 : 함수를 호출하면, 함수 부분의 코드로 점프하고, 리턴하면 다시 원래의 함수로 ex - 예를 들면 main에서 add를 호출하면 pc가 add로 jump해서 실행하고 return을 하면 다시 원래 실행하던 main으로 돌아가기 위해서 return address를 저장하고 있어야 한다
    • stack frame : 함수를 호출하면 함수가 쓸 수 있는 메모리 공간이 할당되는데 그것을 stack frame이라고 한다.
    • 함수를 호출할 때 스택이 늘어나다가, 함수가 반환되면 스택이 줄어든다 → 스택은 커졌다 작아졌다 할 수 있다.
  • Heap : 추가적으로 공간을 할당할 때. 동적 할당. malloc. free

3️⃣ Process State


  • 프로세스의 상태를 OS가 관리해줘야 한다.
  • 그 종류는 OS의 종류에 따라 다르다. OS-dependent
  • 언제 상태가 바뀌는지 알고 있어야 한다.

  • New : 프로세스가 만들어져서 시스템에 들어왔고, 실행되려면 프로세서를 받아야 한다. 아직 프로세서 못 받음
  • Ready : 프로세서가 없어서 기다리고 있는 상태. 프로세스가 프로세서 할당 받기 기다리는 상태
  • Running : Schedular가 선택되어서, 프로세서가 돌아가는 상태
    • 싱글 코어라면 running이 1개 뿐
  • waiting : 파일을 디스크에서 읽어올 때, I/O 등등 기다릴 때
  • terminated : 프로세서가 최종적으로 exit

4️⃣ Process Control Block (PCB)


  • state를 저장하기 위한 stucture(구조). OS가 프로세스마다 PCB를 관리.
  • 프로세스에 대한 정보 저장하기 위한 data structrue (representation of a process)
  • Kernel이 관리하는 메모리 → 프로세스가 관리하는 메인 메모리의 위쪽에 위치하고 있다. 아무나 접근 불가능.
  • 프로세스의 개수에 맞게 PCB가 있다.

  • process state : 프로세스 상태
  • process number : 프로세스 수
  • program counter : register가 잇다는 것이 아니라, register의 값을 저장하는 것이다. register 값이 계속 없데이트 될텐데, 그 값들을 backup해둔다고 생각하면 된다.
  • memory limits : 메모리 얼마나 쓸 수 있는지
  • list of open files

5️⃣ Process Scheduling


  • 엄청 많은 프로세스 → 스케쥴링 역할도 중요

  • 어떤 CPU 코어에 어떤 프로세스를 실행시킬지 결정해준다.

  • 최대한 CPU를 활용해서 낭비되는 시간이 없도록 하는 것이 주요 목표

  • 큐(Queue)를 활용한 스케쥴링

    • 프로세스 할당은 큐 순서 말고, 알고리즘이 알아서

    • wait queue는 상황에 맞게 여러개 있을 수 있다.

    • wait queue에서 나오면 ready queue로 간다.

    • Ready queue : 1개

    • Wait queues : 여러개

    • Queuing Diagram

6️⃣ Context Switch ⭐️


  • Context Switch = CPU가 어떤 프로세스를 수행하다가 다른 프로세스로 넘어가는 것
  • Old Process : P0을 중단 하기 위해, P0의 PCB에 실행 중인 정보를 저장 (→ save the architectural state )
  • New Process : P1이 예전에 실행되었던 데이터를 PCB에서 불러온다. (→ load the saved state )

어떤 것을 백업?

  • Context : Program Counter + Registers
  • pure overhead ; 관리를 위해 드는 추가 cost.
    • OS가 PCB를 잘 관리하기 위해 정보를 추가로 저장 → 상태 전환이 더 빠르게

cf. 심화) Time dependent on hardware support

  • 컨텍스트 스위치 값이 hw support에 따라 다르다. → 한 CPU에 여러개의 Register를 제공 = 여러개 Context를 한번에 로드 가능 → 불러왔다가 다시 저장할 필요 없이, 프로세스 안에서 왔다갔다 → hyperthreading
  • 각 코어가 두 개 이상의 쓰레드를 처리할 수 있다고 여긴다 → Logical(virtual) cores (↔ physical cores )

7️⃣ Operations on Processes : Process Creation


  • 생성하는 방식 : Parent 프로세스 → child 프로세스

    • 리눅스 PCB 구조체를 보면 parent라는 포인터가 있어서 부모 프로세스의 PCB를 가리키고 있다.
    • pid(process identifier)를 통해 프로세스를 구분. 자식은 부모 프로세스의 pid 값을 저장하고 있다.
  • 생성, 관리 방법은 오에스 마다 다르다 → 다양한 옵션이 있다.

    • Resource Sharing - 전부, 일부, 없음
    • Execution - 동시에(같이), 부모가 …
    • Address space - 복제, 자체 프로그램

🔎 Example

  • fork() : 새 프로세스 생성하는 system call
  • exec() : fork 이후 프로세스 메모리 공간을 새 프로그램으로 바꿔주는** system call
  • wait() : parent 프로세스가 child 프로세스의 종료를 기다리기 위해 사용하는 system call
  • code example

8️⃣ Operations on Processes : Process Termination


✔️ exit()

  • exit() : 프로세스가 마지막 명령을 수행한 후 OS에게 종료를 알려주는 System call
    • exit()이 되면
      1. 자식이 부모에게 output data를 보낸다. (→child가 끝났는지를 wait를 통해 알 수 있다.)
      2. 프로세스의 리소스들이 OS에 의해 deallocated(반납) 된다.
    • child가 exit되면 terminated 상태가 되고, 이것이 system call로 parent로 전달되면, wait이었던 parent는 다시 ready 상태가 된다.

✔️ abort()

  • abort() : 프로세스를 강제 종료해주는 system call

    • 부모 프로세스가 자식 프로세스를 종료시키는 3가지 경우
      1. 리소스를 너무 많이 쓰면(할당 리소스를 초과)
      2. child에게 할당된 task가 더이상 필요X
      3. parent가 존재하는데 OS가 parent가 종료될 때 child가 계속되는 걸 허용하지 않을 때
      • child 프로세스의 동작이 이상할 때 (→ 이것도 부모가 자식 상태를 알 수 있어야 함)
  • cascading termination (연쇄 종료)

    • parent가 종료되면 child가 존재할 수 없게 (→ 몇몇 시스템에서는 부모 없이 자식 프로세스가 실행 될 수 없어서 종료)
    • child가 다 종료되어야 parent가 종료될 수 있도록. 차례대로 위로 올라가면서 terminate.
  • zombie & orphan process

    • wait() system call → 프로세스 상태 정보종료된 프로세스의 pid를 반환
      pid = wait(&status);
      → 부모 프로세스는 wait system call을 이용하여 child 프로세스의 종료를 기다린다.
    • 프로세스가 종료하면 사용하던 자원은 OS가 다시 가져가는데, 프로세스의 종료 상태가 저장되는 프로세스 테이블의 해당 항목은 부모 프로세스가 wait()를 호출할 때까지 남아있게 된다.
    • 부모 프로세스가 wait를 안 해주면 zombie가 된다. : 프로세스는 종료되었지만 부모 프로세스가 아직 wait()를 호출하지 않은 프로세스 = 좀비 → wait를 하지 않으면 반환할 때 state를 반환할 곳이 없게 된다.
    • parent 프로세스가 wait()를 호출하지 않은 상태로 종료해버리면 갈 곳 없는 부모가 없는 orphan process 가 된다.

9️⃣ Interprocess Communication (Models)


  • 프로세스 간의 커뮤니케이션, cooperating → 다른 프로세스의 영향을 받을 수 있다.

  • 협력할 수 있도록 만든 이유?

    • Information sharing : 두 개의 프로세스가 하나의 variable을 공유
    • Computation Speedup : 여러 프로세스 → task를 병렬적으로 처리
    • Modularity : 테스크를 분리 → 관리가 쉽다
    • Convenience : 분리해서 관리 → 편리함
  • 프로세스 간의 통신(IPC) 방식 크게 두 가지→ 두 방식의 차이점, 비교! 가 중요

    • Shared memory : 원래 자신의 프로세스 공간 자체는 보호받아야하는데, 공유하기 위해서, 다른 프로세스가 접근할 수 있도록
    • Message Passing : 커널이 메세지 큐 관리 → 보내고 싶은 프로세스가 메시지 큐에 메세지를 집어 넣으면 → 메세지를 읽어와서 추가적으로 공유 (커널 안에 메일 박스가 존재한다. 프로세스가 편지를 남겨두고, 받는 애가 읽는다)

🔟 IPC - Shared Memory


  • 프로세스 사이에 공유되는 메모리 공간이 존재
    • 커널(OS)이 직접 관여(control) X → User process 의 제어(control)로 통신 이뤄진다
  • synchronize(동기화) 문제
    • p1과 p2가 모두 shared memory 공간에 접근 가능 → p1이 쓴 데이터를 p2가 덮어버릴 수 있다. → 프로세스간의 synchronization을 통해 의도치 않게 수정되거나 덮어지는걸 방지해야함

🔎 Example

  • Producer(data 만듬) ↔ Consumer(data 사용함)
  • 둘 사이에 shared buffer 존재
  • in, out으로 circular buffer의 시작과 끝을 표시

🔎 POSIX

  • Shared Memory API

  • 프로세스가 shared memory segment 생성
    • shm_fd = shm_open(name, O_CREAT, O_RDWR, 0666);
      • 공간 이름, permission 등을 설정
  • 오브젝트의 크기 설정
    • ftruncate(shm_fd, 4096);
      • file descripter, byte 설정
  • shared memory object에 파일 포인터에 메모리를 맵핑
    • char *buf = mmap();
      • mmap()에 의해 반환되는 포인터를 사용해서 공유 메모리에 읽고 쓸 수 있다.

🔟 IPC - Message Passing

  • shared memory는 서로 메모리를 어디에 쓸 줄 알았지만, 이거는 공유 변수에 의지X.

  • 직접적으로 send(message), receive(message)

  • 메세지 크기는 고정될 수도 있고, 바뀔 수도 있음

  • 커널이 관리해주는 communication link 가 있어야 메세지를 주고받을 수 있다.

    • 서로 포트가 있어서, 포트를 열어서 어쩌고 저쩌고 하는 것처럼 커널에서 링크를 열어서 메세지를 주고받는다.
  • Physical(물리적) 구현

    • shared memory에도 가능인데 차이는 send, receive로 메세지 단위로!!!!!
    • Hardware bus, Network(Socket)
  • Logical(논리적) 구현

    • direct : 보내는 사람을 지정해놓는것 → send(Q, message); (message target의 유무 차이)
    • indirect : 일단 박스에 메세지를 넣어놓고, 필요한 사람이 가져다 쓰는 것 → send(message);
    • asynchronous : 메세지를 보내기만 한다. 받았다는 것 확인 안 하고 다른 작업 수행
    • synchronous : 동기 방식. 내가 그 메세지를 보낸 것을 받았다는 것을 확인해야 하는 것.
    • buffering : 메세지를 여러개 보낼 때, 버퍼에 메세지를 보관하거나, …
profile
가볍게 재밌던 거 기록해요

0개의 댓글