본문 바로가기
CS

운영체제 - 반효경 #4 Process Management

by unknownomad 2023. 3. 17.

# 4-1 Process Management 1

프로세스 생성

부모 프로세스

  • 부모가 자식을 만드는데, 보통 복제 생성
  • 부모 1이 자식 여럿을 만들 수 있음 – 트리 형태
  • 원칙적으로 자식과 자원을 공유하지는 않음
    • 생성된 자식은 부모와 별개의 프로세스 = 경쟁 관계
    • 공유하지 않는 모델이 일반적
  • 부모가 기다리는 = wait = blocked 되는 모델도 있음

자식 프로세스

  • 자식은 부모의 주소 공간을 그대로 복제
  • 운영체제에 있는 데이터인 PCB, 자원 등도 똑같이 복사
  • 이론적으로 이렇게 복제 생성하면 컴퓨터 내의 모든 프로세스는 다 같은 일만 해야 함
  • 그렇기에 일단 복제 후 그 복제된 곳에 새로운 프로그램을 덮어씌울 수 있음
  • 이렇게 서로 다른 프로그램이 한 컴퓨터에 존재 가능
  • 복제 생성 = fork 시스템콜
  • 복제 후 다른 프로그램으로 덮어 씌우기 = exec 이라는 시스템콜
  • fork 와 exec 은 독립적이기에, 복제 후 덮어씌우지 않을 수도 있음
  • exec 하면 완전 새로운 프로그램으로 바뀔 수 있음
  • 사용자 프로세스가 직접 다른 프로세스를 생성하는 게 아니라, 운영체제 통해 생성
    • 시스템콜이니까, 자식을 낳아달라 부탁하면 운영체제가 대신 낳아주는 역할

 

프로세스 종료

exit

  • 메서드 마지막을 중괄호로 닫으면 프로그래머가 명시적으로 exit 시스템콜 하지 않아도 컴파일러가 중괄호 닫는 지점에 exit 이라는 시스템콜을 자동으로 넣어줌
  • exit 으로 프로그램 종료되면 자식이 부모에게 어떤 데이터를 보냄
  • 프로세스의 세계에서는 부모가 자식을 낳으면, 자식이 먼저 종료돼야 하기에, 프로세스가 종료되면 부모에게 데이터가 전달됨 = 그게 wait 시스템콜로 전달하는 것
  • 자발적으로 프로세스가 종료되면 exit 시스템콜 해주면 됨

abort

  • 비자발적으로 프로세스 종료되는 경우 = abort
  • 자원의 할당치를 넘어선 요구를 하면 부모가 강제로 죽임
  • 자식을 왜 낳았느냐? 일을 시키려고 : 자식에게 더 시킬 일이 없으면 부모가 자식을 죽임
  • 부모 프로세스가 종료되는 경우 : 그 부모가 낳은 자식들 모두 죽인 후 부모가 죽음

# 4-2 Process Management 2

프로세스 생성

프로세스

  • 복제 생성
  • 여기서의 복제 = 프로세스의 문맥을 모두 복사
  • 부모 프로세스의 주소 공간인 메모리의 코드와 스택을 그대로 복사해 자식 프로세스 생성
  • 부모 프로세스의 CPU 문맥에서 현재 인스트럭션을 언제까지 수행했는지 나타내는 레지스터인 프로그램 카운터 또한 부모 것을 그대로 복사

부모와 자식의 자원 공유

  • 프로세스가 하나 만들어지면 이는 독립적인 프로세스임
    • 원칙적으로는 부모와 자식은 서로 경쟁하며 자원을 더 차지하려는 관계가 됨
  • 원칙보다 조금 더 advanced 한 개념
    • 자식이 부모의 코드, 데이터, 스택을 그대로 카피하면 메모리에 두 카피가 일어남 = 메모리 낭비
    • 부모와 자식의 내용이 똑같으면 당장 카피할 필요는 없음
    • 리눅스나 일부 모델에서는 모든 걸 부모에서 카피하는 게 아니라, 공유할 수 있는 모든 것은 가능하면 그대로 두고 공유함
    • 그렇게 실행하다, 부모와 자식의 내용이 달라지면(사실 별개의 프로세스니까) 그때 부모와 공유하던 메모리 공간의 일부를 자식이 가지게 됨
      • = Copy-On-Write 기법(COW)
      • = Write 발생 시 그때 copy 하겠다
      • = Write 발생(원래 있던 내용 변경)하면 그때 copy 해서(필요한 일부만) 새로운 걸 만들고, 그 전까진 공유된 자원 쓰겠다는 거임

 

  1. 일단 복제
    • 운영체제에게 자식 프로세스 만들어 달라고 요청
    • = 시스템콜
    • = fork
  2. 새로운 걸 덮어씌움
    • 일단 복제 생성 후, 필요한 경우에 새로운 프로그램을 덮어씌움
    • = exec

 

fork() 시스템콜

  • fork 를 사용해 사용자 프로그램이 프로세스를 만드는 코드
  • 운영체제에게 새로운 프로세스 하나 만들어 달라는 요청 = fork 시스템콜

실행 순서

  • 부모에서 fork 실행해 자식 생김
  • 그럼 프로그램 카운터는 fork 를 가리키게 됨
  • 부모는 fork 이후부터 작업 계속 실행하면 되는데, 자식은?
  • 자식도 부모의 프로그램 카운터 정보를 복사 받았기에 fork 이루어진 그 이후부터 실행됨
    • (부모 프로그램의 컨텍스트를 복제하기에)
    • = 자식… 이라기보단 부모1 이 부모2 를 생성한 격
    • = 나도 복제본이 아닌 원본이다! 라고 주장하게 됨
  • fork 를 통한 복제 생성의 문제점이 이거임
    • 운영체제가 복제본 만들어주면 부모와 자식을 구분해야
    • fork 실행 후 부모와 자식의 return value 가 다름
      • 부모는 fork 결과값 > 0
      • 자식은 fork 결과값 = 0
    • 이렇게 원본과 복제본 구분하며 다른 작업을 할 수 있음

 

  • 부모
    • print ➡️ fork ➡️
  • 자식
    • 프로그램 카운터가 fork 를 가리킴 = 나는 print 구문을 실행했다는 기억을 가지고 있으니 이건 실행 안 할 거야
    • fork 이후부터 실행되기에 부모 위치에서의 print 문 실행 안 됨(사실 print 구문은 부모만 실행한 거지만)

 

exec() 시스템콜

exec 시스템콜

  • 어떤 프로세스를 완전 새로운 프로그램으로 태어나게 해줌
  • fork 로 자식 생성 후
    • pid == 0 , 자식이면 execlp 실행 = exec 시스템콜 실행
    • exec = 프로그램의 시작 부분부터 실행, 아예 새로운 삶을 사는 것
    • 한 번 exec 하고 나면 다시 되돌릴 수 없음
    • fork 후 ➡️ 자식에게 새로운 프로그램 덮어씌우기 위해 exec 실행 ➡️ fork 제외, 처음부터 코드 실행

  • fork 없는 두 번째 코드
    • 제일 마지막 print 구문은 실행 안 됨
    • exec 실행하면 아예 새로운 프로그램이 되어버리기에 밑 코드는 실행할 수 없음 = 되돌아올 수 없음

  • 세 번째 코드
    • 1 ➡️ echo 실행 ➡️ 3 출력(2는 출력 불가)
    • execlp 할 때는 프로그램 이름 두 번 적어주고, 그 프로그램에 전달할 argument 를 순차적으로 적어준 후, (char *) 0 적어줌

 

wait() 시스템콜

 

exit() 시스템콜

 

프로세스와 관련한 시스템콜

wait() 시스템콜

  • 부모와 자식이 병렬적으로 실행되는 경우도 있지만
  • 자식 프로세스를 낳은 후, 그 자식이 일을 다 수행하고 종료될 때까지 부모 프로세스가 기다리는 실행모델도 있음

 

프로세스 간 협력

독립적 프로세스

  • 원칙적으로 독립적임
  • 자식 낳고 나면 자기 먹고 살 건 알아서 챙기라 함
  • 직접 코드, 데이터, 스택 만들고 CPU 할당 받으려 노력해야 함
  • 원칙적으로 하나의 프로세스가 다른 프로세스에 영향 미치지 못함(부모가 자식 죽이는 경우 제외)

 

협력 프로세스

  • 협력해야 효율적으로 실행되는 경우에는 이렇게 진행
  • 서로 정보 주고받으며 실행

 

프로세스 간 협력 메커니즘

  • IPC = 정보를 주고받을 수 있는 방법
  • IPC 에는 두 가지 방법이 있음 : message passing / shared memory
  • Message passing
    • 프로세스 a 가 프로세스 b 에 메시지 전달 후
    • 이에 영향 받아서 프로세스 b 가 실행
    • 필요하면 프로세스 a 에게 메시지 전달 등
    • 내가 다른 프로세스에게 메시지 전달할 수 있는 방법은 원칙적으로 없음
    • 프로세스 간 전달 불가
    • 그렇기에 커널 통해 메시지 전달
    • 커널이 메신저 역할
  • Shared memory
    • 원칙적으로 프로세스는 독자적 주소 공간을 가지고 있기에
    • 코드, 데이터, 스택을 각자 가지고 있어 자기 주소 공간만 볼 수 있는데
    • Shared memory 는 그럼에도 불구하고 일부 주소 공간을 두 프로세스가 공유하는 방식
    • 프로세스 a, b 각자 코드, 데이터, 스택 개별적으로 가지고 있으나, shared memory 라는 공유 영역을 물리적으로 별도로 매핑해둠으로써 각자의 주소 공간에서 같이 쓸 수 있음
    • Shared memory 는 서로 신뢰할 수 있을 때만 사용
  • Thread
    • 한 프로세스의 주소 공간에서 여러 쓰레드들이 협력
    • 쓰레드들 간에는 완전한 협력 가능
    • 주소 공간이 완전 공유됨

 

Message Passing

Message passing

  • 다른 프로세스에 정보 전달할 때 운영체제의 커널 통해 메시지 보냄
  • 직접/간접 통신 모두 사용자 프로세스 간 무언가 전달 시, 운영체제 커널은 반드시 필요
  • 다만 인터페이스 측면에서 직접/간접 방식에 차이가 있을뿐

 

Direct communication

  • 직접 통신
  • 메시지 전달하는 프로세스가 어떤 프로세스에게 무슨 메시지를 전달한다는 걸 명시

 

Indirect communication

  • 간접 통신
  • 메시지를 전달하는 프로세스가 직접 명시하지 않고, 메일박스에 정보 넣음
  • 메일박스에서 정보 꺼내 보는 누군가가 지정된 게 아님
  • 메일박스에서 아무나 꺼내가라

 

Interprocess Communication

 

CPU and I/O Bursts in Program Execution

Load store, add store, …

  • CPU 에서 인스트럭션을 수행하는 기계어

I/O

  • 오래 걸리는 작업
  • 이 작업 동안 CPU 는 다른 프로세스가 사용
  • CPU 를 쓰는 단계와 I/O 작업이 번갈아 작동

CPU burst

  • CPU 쓰는 단계

I/O burst

  • I/O 작업 진행
  • 주로 사람이 사용하는 프로그램에서 CPU burst 와 I/O burst 활발히 일어남
  • 한 작업 수행 후 I/O 통해 데이터 가져와 사용자의 화면에 뿌려주는 등

 

CPU-burst Time의 분포

I/O bound job

  • CPU를 짧게 쓰는 대신 빈도가 잦음
  • 얘가 문제야
  • 주로 interactive 한 작업, 사용자 관련 작업 진행
  • 가능하면 사람과 작업하는 이 작업에 더 CPU를 자주 줌으로써 대기시간을 줄여주고 사용자의 답답함을 낮추는 게 효율적 = CPU 스케줄링

CPU bound job

  • CPU를 길게 쓰는 대신 빈도가 낮음

 

프로세스의 특성 분류

CPU bound job

  • 중간에 I/O 작업 없어서, CPU를 연속적으로 쓸 수 있음

 

CPU Scheduler & Dispatcher

CPU scheduler

  • 이건 하드웨어가 별도로 있나? 프로그램이 별도로 있나? 이런 걸 잘 알아야!
  • 운영체제 안에 CPU 스케줄링하는 코드가 있는데, 그 부분을 일컬음
  • CPU를 누구에게 줄지를 결정하는 코드
  • 우선순위에 기반한 스케줄링

Dispatcher

  • 실제 CPU를 주는 과정
  • Context 저장 후 넘겨줘야
  • CPU 안에 레지스터 값 세팅 후 넘기기

 

댓글