지나공 : 지식을 나누는 공간

[직무인터뷰] 운영체제 이야기 본문

Tech Interview

[직무인터뷰] 운영체제 이야기

해리리_ 2021. 6. 7. 16:44

프로세스와 스레드란?

  • 프로세스 : 실행 중에 있는 프로그램을 의미로 스케줄링의 대상인 task(작업)과 같은 의미로 사용된다.
    • 각각 독립된 메모리 영역을 할당받고, 프로세스마다 최소 1개의 스레드(메인스레드)를 가진다.
    • 각 프로세스는 별도의 주소 공간에서 실행되어서 다르 프로세스의 변수나 자료구조에 접근할 수 없다.
    • 한 프로세스가 다르 프로세스에 접근하려면 IPC를 사용해야 한다.(inter process communication)
  • 스레드 : CPU 사용의 기본 단위로, 프로세스 내에서 실행되는 여러 흐름의 단위다.
    • 프로세스 내에서 각각 stack만 따로 할당받고 code, data, heap은 공유한다.
    • 스레드가 여러 개면 멀티스레드이고, 멀테스레드에서는 각 스레드끼리 프로세스의 일정 메모리를 공유한다. 따라서 프로세스의 Context Switching보다 스레드 Context Switching이 더 빠르다. 그래서 멀티프로세스보다 멀티스레딩이 더 빠르다
      • Context Switching이란?
        현재 진행하고 있는 task(프로세스나 스레드)의 상태를 저장하고 인터럽트에 의해 다른 task를 읽어  새로운 task의 context 정보(프로세스의 주소, 쓰일 데이트 등등)로 교체하는 작업이다. context는 cpu가 다루는 task에 대한 정보이다. PCB(Process Control Block)로 관리되는 정보이고 레지스터에 저장된다.

프로세스의 메모리 영역

  • Code : 실행할 프로그램의 코드가 저장됨
  • Data : 전역변수와 static 변수가 저장되고 프로그램의 시작부터 종료까지 남아있다.
  • Heap : 동적할당과 동적해제가 이뤄지는 곳으로 사용자가 직접 관리할 수 있는 메모리 영역임.
  • Stack : 함수 호출부터 함수 호출의 종료까지 쓰이는 지역변수, 매개변수가 저장된다.

힙이나 스택 사이즈가 정해져 있고, 이걸 넘어갈 때 스택오버플로우가 발생한다.

이걸 방지하는 방법은 두 가지.

1. 넘어가지 않게 코딩을 한다.

2. 힙의 최대 사이즈를 늘린다.

왜 스택에 함수와 관련된 변수를 넣을까? 힙에 안하고? 자료구조랑 관련지어 생각해서 말해봐라

스택의 특징을 떠올려보자. 스택은 가장 마지막에 들어온 게 가장 빨리 나간다. 함수를 호출할 때에도 가장 마지막에 호출하는 함수가 끝나면 그 함수와 관련된 데이터를 가지고 있을 필요가 없다. 마치 괄호연산을 스택에 저장하는 것과 비슷하게, 마지막에 열린 게 가장 먼저 끝난다. 

 

스택에 메인함수가 있는데 이걸 진행하다가 어떤 함수를 호출하면 그 함수호출로 갈 때 그 관련 데이터가 main위에 쌓이고 그게 끝나면 다시는 해당 데이터를 쓸 일이 없으니 스택에서 빼 버린다. 이런 내용을 구현하기에 가장 맞는 자료구조가 스택이다.

프로세스의 상태 변화

  • New를 통해 프로세스가 처음 생성되고 이후 Ready Queue에 들어간다.
  • 스케줄러에 의해 Ready <-> Runnig으로 상태가 변한다.
    • Ready가 Runnig이 되는 걸 Dispatch
    • Running이 Ready가 되는 걸 Timeout이라고 한다.
  • I/O Event가 발생하면 Running에서 -> Blocked로 변함
  • Blocked에서 I/O Event가 종료되면 Ready
  • 프로그램이 다 끝나면 Release되면서 Exit가 된다.

교착상태(DeadLock)

두 개 이상의 프로세스나 스레드가 서로 자원을 기다리면서 무한히 기다리게 되는 상태.

교착 상태는 두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있어서, 다음 단계를 진행하지 못한다.

프로세스1이 리소스1을 가지고 연산한 뒤 이를 기반으로 리소스2를 사용해야 해서 리소스1을 잡은 채로 리소스 2를 대기한다. 프로세스2는 리소스2를 가지고 사용한 뒤 이를 기반으로 리소스1을 사용해야 하는데 리소스1은 프로세스1이 잡고 있어서 접근을 못한다. 이렇게 서로 리소스를 놔 주지 못하는 상태다.

DeadLock 발생 조건 -> 외워라..

  • 상호배제(Mutual Exclusion)
    • 한 자원에 대한 여러 프로세스의 동시 접근을 불가능하게 만들어서 데드락이 발생한다.
    • 내가 사용하고 있으니까 다른 사람들은 쓰지마! 이니까 서로가 서로의 자원을 필요로 하면 큰일난다...
  • 점유와 대기(Hold and Wait)
    • 하나의 자원을 소유하고 다른 프로세스 혹은 스레드의 자원을 요청하는 상태
    • 내가 하나를 사용하고 있지만 다른 자원도 사용해야 해서 다른 자원도 요청하고 있는 상태(위 그림과 동일)
    • 그래서, 내가 하나를 잡고 있는 상태에서 다른 것도 사용하려고 할 때에 데드락이 발생한다는 의미임.
  • 비선점(Non Primitive)
    • 프로세스나 스레드에게 주어진 자원은 해당 프로세스나 스레드가 스스로 놓기 전까지는 놓게 만들 수 없다.
  • 환형 대기(Circle wati)
    • 각 프로세스가 다음 프로세스가 요구하는 자원을 갖고 있는 상태다.
    • A는 B가 필요한데 B는 C가 필요하고 C는 A가 필요할 때

이 네가지를 충족할 때 데드락이 발생한다.

그럼 DeadLock 해결은 어떻게 하는데?

현실적으로 쓰이는 방법은 탐지와 복구다.

  • 예방 : 미리 방지하는 것. 이건 프로그래머의 재량임...
  • 회피 : 교착 상태에 빠질 가능성이 있는지 확인 후 자원 할당. 그니까 자원을 할당하기 전에 이걸 필요로 하는 다른 애가 더 있는지 찾아본 뒤에 없을 때 이 자원을 할당하는 방법. 근데 현실적으로 이 방법을 쓰긴 어려움
  • 탐지 : 교착 상태 발생을 허용한 뒤 탐지한다. -> 복구로 이어짐
  • 복구 : 프로세스 중지. 희생자 최소의 원칙에 맞게 최소의 프로세스를 종료시켜서 복구한다.

CPU 스케줄링 방법은?

선점형, 비선점형이 있음.

선점은 우선순위가 높은 게 들어오면 현재의 것을 중지시키고 우선순위가 높은 것을 처리한다. (VIP가 오면 먹고 있는 애도 내쫓기)

비선점은 한번 프로세스가 들어오면 할당이 끝날 때까지 다른 프로세스가 들어오지 못한다.

 

  • FCFS(First In First Out)
    • 먼저 들어온 것을 먼저 처리하겠다. 비선점형임 (우선순위 높고 그런거 신경 안쓰고 무조건 먼저 오면 먼저 처리)
    • 공평성은 유지되지만 짧은 작업이 긴 작업이 끝날 때까지 기다려야 하고, 중요한 애가 안 중요한 애의 처리가 끝날 때까지 기다려야 한다.
    • 장점 : 공평하다.
    • 단점 : 평균 응답시간이 길어진다.
  • SJF(Shortest Job First)
    • 금방 처리할 수 있는 애들부터 처리한다. 비선점형
    • 평균 대기시간이 가장 짧아지는 최적의 알고리즘이다.
    • 하지만 단점은 실행 시간이 긴 프로세스는 cpu를 할당받지 못한 채로 무한하게 대기하는 현상이 발생한다. starvation이 일어난다. 작업이 긴 애는 계속 짧은 애 들어올 때마다 또 양보하고, 기다리다가 새로 들어온 애가 또 나보다 짧으면 또 대기하고... 계속 양보만 하다가 굶어 죽는게 starvation임.
  • SRT(Shortes Remaining time First)
    • 선점형. 현재 상태에서 우선순위를 정해서 지금 진행 중인 애가 있더라도 우선순위 높은 애에게 할당한다.
    • 새로운 프로세스가 도착할 때마다 새로운 스케줄링이 이뤄진다.
    • 현재 실행 중인 프로세스의 남은 시간과 대기큐에 있는 것의 실행 시간을 비교해서 더 짧게 걸리는 프로세스에게 CPU를 할당한다.
    • 비선점인 SJF를 선점 형태로 변경한 것으로, 잦은 선점(진행 중인 애 자리를 뺏기)으로 인해 Context Switching 부담이 있다. 우선순위가 낮은 애는 계속 진행중이더라도 자리를 뺏길 수 있다 보니 starvation이 일어날 수 있다. SJF랑 똑같이, 덩치 큰 애는 영원히 실행될 수 없다.
  • RR(Round Robin)
    • 각 프로세스는 동일한 크기의 할당 시간(time quantum)을 갖는다.
    • 할당 시간이 지나면 프로세스는 선점 당하고(자리 뺏기고) Ready Queue의 맨 뒤로 들어간다.
    • 주의사항
      • 설정한 time quantum이 너무 길면 그냥 FCFS랑 같아진다. 먼저 들어온 게 그냥 먼저 끝까지 처리되고 나가버릴 테니까.
      • 그렇다고 너무 짧아지면 계속 Context Switching을 해야 하니까 오버헤드가 발생한다.
  • Priority Scheduling
    • 우선순위가 가장 높은 프로세스에게 CPU를 할당한다. 우선순위를 정수로 표현하고 숫자가 작을 수록 우선순위가 높다. 두 가지 방법으로 구현이 가능하다.
    • 선점형 스케줄링 방식으로 구현한다면 먹고 있어도 상사를 위해 자리를 뺏긴다. 
    • 비선점형 스케줄링 방식으로 구현한다면 더 높은 우선순위의 프로세스가 도착했을 때 Ready Queue에서 맨 끝은 아니고 Head에 넣는다. 우선순위가 높은 앤데 먹고 있는 애를 쫓아낼 순 없으니 걔만 다 먹으면 바로 시작할 수 있도록. 

우선순위가 낮은 JOB은 계속 CPU를 할당받지 못하는 starvatation은 어떻게 해결할까?

Aging 기법을 통해 대기시간이 길어질수록 우선순위를 높여주는 방법이 있다.

 

세마포어, 뮤텍스, 페이징/세그먼트, 동기/비동기는 수정할 때 추가하겠다.

728x90
Comments