[OS/JAVA] 프로세스 스케줄링 시뮬레이터

권유정·2024년 5월 23일

CS

목록 보기
1/1
post-thumbnail

개요

프로세스 스케줄링 알고리즘은 단순히 운영체제의 영역을 넘어서, 여러 자원을 필요로 하는 다양한 시스템과 응용 프로그램에서도 중요하게 활용되는 것처럼 보였다. 효율적인 자원 관리와 최적의 성능을 위해 다방면으로 쓰일 것으로 느껴졌다.
따라서 이전 3학년 OS과목의 과제였던 여러 개의 다중 처리 코어와 제한된 종류 및 수량의 공유 자원을 가지는 시스템에서의 스케줄링 알고리즘을 재구현해보려한다.
그때는 Python으로 진행했었지만, 전체 코드를 Java 리팩토링하고 재작성해보면서 OS 구조를 더 깊게 이해하고자 했다.


스케줄링에 대해

  • 스케줄링 : 현재 CPU를 사용하고 있는 프로세스를 다른 프로세스로 전환함으로써 모든 프로세스가 효율적으로 CPU 시간을 사용할 수 있도록 하는 것.
  • 다중 프로그램 운영체제에서 중요한 역할을 함
  • 스케줄링의 필요성 : CPU 버스트와 IO 버스트의 균형
    프로세스들은 CPU 버스트(계산 작업)와 IO 버스트(입출력 작업) 사이에 상이한 패턴을 보인다. 만약, CPU를 많이 사용하지 않고 입출력 작업이 많은 프로세스가 CPU를 독점하게 되면, 다른 프로세스들은 CPU를 효율적으로 사용하지 못하고 대기 상태에 머물게 된다.
  • 스케줄링의 목적과 효과
    • CPU 이용률 최대화: 스케줄링 알고리즘은 CPU가 가동 중지 상태에 빠지지 않도록 하여, CPU 이용률을 최대화한다.
    • 시스템 효율성 향상: 스케줄링을 통해 CPU의 작업 처리가 균등하게 분배됨으로써, 모든 프로세스가 공정한 시간 안에 자원을 효과적으로 사용할 수 있다.

프로세스 스케줄링 시뮬레이터

🐱 github 주소


  • 시뮬레이션 시스템은 여러 개의 다중 처리 코어와 제한된 종류 및 수량의 공유 자원으로 구성된다.
  • 이 시스템은 프로세스들이 생성되어 자원 할당 관리자(Resource Manager)로부터 자원을 할당받고, CPU에서 실행되는 환경을 고려한다.


시스템의 주요 구성 요소들과 그 특성
이 구조는 프로세스가 자원을 요청하고, 자원 할당 관리자가 이를 처리하여 각 CPU 준비 큐에 프로세스를 배정한 후, 각 CPU가 프로세스를 실행하는 전체적인 과정을 나타낸다. 자원 할당 관리자는 교착 상태를 피하기 위해 자원을 관리하고, CPU 준비 큐는 특정 스케줄링 알고리즘에 따라 프로세스를 선택한다.

  1. 프로세스 (Process)
    • 일정 시간 동안 실행된 후 종료
    • 실행을 위해 공유 자원을 필요로 함.
    • 실행 시간과 필요한 자원의 종류 및 수량은 프로세스가 생성될 때 결정
    • 자원을 할당받기 전, 자원 할당 대기 큐에서 필요한 자원을 할당받기를 기다림.
    • 자원을 할당받은 후, CPU 대기 큐에서 실행되기를 기다림.
    • 종료될 때까지 실행과 대기를 반복
  2. 자원 할당 대기 큐 (Resource Allocation Waiting Queue)
    • 프로세스가 필요한 자원을 할당받기 위해 대기하는 큐
    • 자원 할당 관리자가 프로세스에게 자원을 할당하기 전까지 프로세스가 대기하는 곳
    • 프로세스는 자원 할당을 받으면 CPU 준비 큐로 이동
  3. 자원 할당 관리자 (Resource Manager)
    • 시스템이 교착 상태에 빠지지 않도록 관리
    • 시스템이 가지고 있는 자원, 프로세스들에 할당된 자원, 할당 가능한 자원의 종류와 수량을 파악
    • 자원 할당 대기 큐에 있는 프로세스들 중 자원을 할당받을 수 있는 프로세스에 자원을 할당
    • 특정 CPU의 준비 큐에 프로세스를 넘김.
    • 가장 짧은 길이를 가진 준비 큐에 프로세스를 할당
  4. CPU 준비 큐 (CPU Ready Queue)
    • 특정 CPU와 1:1로 대응되며, 대응되는 CPU에서 실행되기를 기다리는 프로세스들을 담고 있는 큐
    • 모든 CPU 준비 큐는 동일한 스케줄링 알고리즘을 가지고 있음.
    • 해당 CPU 알고리즘에 따라 다음에 실행될 프로세스를 선택
    • CPU가 다음 작업을 실행할 수 있는 상태가 되면 그 프로세스를 CPU에 넘김.
  5. CPU(프로세서)
    • 실제로 프로세스를 실행하는 처리 장치
    • 각 CPU는 자신에게 할당된 준비 큐에서 프로세스를 받아 실행
    • CPU는 스케줄링 알고리즘에 따라 준비 큐에서 프로세스를 선택하여 실행

시뮬레이터 클래스 다이어그램


주요 클래스와 역할

  1. ProcessSimulator
  • 역할: 시뮬레이션의 주체로, 시간의 흐름을 관리하고 프로세스의 생성 및 스케줄링을 담당
  • 주요 메서드:
    • simulate(): 시뮬레이션을 시작하고 각 타임 슬롯에서 프로세스를 실행 과정을 진행
    • processTick(): 하나의 시간 단위를 처리하며, 프로세스를 디스패치하고, 자원을 할당하며, 프로세스 상태를 업데이트
  1. Processor
  • 역할: 개별 프로세서를 나타내며, 각 프로세서의 작업 대기열을 관리
  • 메서드:
    • runProcess(): 현재 프로세서에 할당된 프로세스를 실행
    • checkAndAssignProcess(): 스케줄링 알고리즘에 따라 실행 프로세스 선택
  1. Process
  • 역할: 실행될 각각의 프로세스, 필요한 자원과 실행 시간 등의 정보를 포함
  • 메서드:
    • runProcess(): 프로세스를 주어진 시간만큼 실행
    • assignResource(): 프로세스에 필요한 자원을 할당
    • getRemainingTime() : 현재 남은 실행 시간 반환
  1. ResourceManager
  • 역할: 자원의 할당 및 안전 상태 확인, Banker's algorithm을 변형하여 안전한 자원 할당을 판단
  • 메서드:
    • getProcessToAssignResources() : 현재의 가용 자원 정보와, 대기 중인 프로세스들이 필요로 하는 자원 정보를 토대로 [상태정보, 프로세스 목록]를 반환
    • bankerALG(): 요청된 자원이 안전하게 할당될 수 있는지 확인하고, 할당할 수 있다면 해당 자원을 할당
      • 상태정보: 자원 할당 가능 여부를 나타내는 값이며 상태에 따라 다음의 값을 나타냄
        • 1: 자원을 바로 할당 할 수 있는 상태
        • 0: 어느 정도의 시간이 지난 후 자원을 할당 할 수 있는 상태
        • -1: 대기 중인 프로세스 중에 자원을 과도하게 요청하는 프로세스가 있어 자원 할당이 불가능한 상태
      • 프로세스 목록 : 대기 상태의 프로세스들 중 준비 상태로 잔환되는 프로세스들
    • checkSafety() : 안전상태 확인 및 안전 순서 반환
  1. TaskScheduler
  • 역할: 스케줄링 알고리즘에 따라 프로세스를 선택 - FCFS, RR(Round Robin), SJF(Shortest Job First), SRJF(Shortest Remaining Job First)
  • 메서드:
    • getProcessIdxFromQueue(): 현재 조건과 스케줄링 알고리즘에 따라 실행할 프로세스의 인덱스를 결정


핵심 코드 설명: 프로세스 스케줄링 시뮬레이터

ProcessSimulator 클래스

  • 이 클래스는 프로세스 스케줄링 시뮬레이터의 핵심 역할을 담당.
  • 주요 기능 : 프로세스 생성, 스케줄링, 자원 할당 및 시뮬레이션 실행.

주요 필드 및 메서드

  • 필드

    • currentTime: 현재 시뮬레이션 시간을 추적
    • isSolvable: 시스템이 해결(스케줄링, 실행) 가능한 상태인지 여부
    • processorList: 프로세서 리스트
    • processWaitingList: 자원 할당을 기다리는 프로세스 리스트
    • processDispatches: 프로세스 디스패치 리스트
    • currentResources: 현재 가용 자원을 추적
    • random: 랜덤 값을 생성 객체
  • 메서드

    • initializeProcessors(): 프로세서 리스트를 초기화
    • generateRandomDispatchSchedule(): 랜덤한 프로세스 디스패치 스케줄을 생성
    • simulate(): 시뮬레이션을 실행
    • processTick(): 하나의 시간 단위를 처리하고, 프로세스 디스패치, 자원 할당, 상태 업데이트 등을 수행
    • processResourceAssignments(): 자원 할당을 처리
    • checkAndAssignProcesses(): 프로세서에 프로세스를 할당
    • cleanupProcesses(): 완료된 프로세스를 정리하고 자원을 반환

코드

  • simulate(): 시뮬레이션을 시작하고 각 시간 단위에서 processTick()을 호출하여 프로세스를 처리
  • processTick(): 프로세스 디스패치, 자원 할당, 프로세스 상태 업데이트 등을 수행
public void simulate() {
    System.out.println("#PROC #TICK : PROC ID     | # CPU WAIT | # WAITING QUEUE | CURRENT RESOURCES");
    System.out.println("-------------------------------------------------------------------------------");

    while (isSolvable) {
        if (processTick()) break;
    }
    System.out.println("Finish!");
}

private boolean processTick() {
    boolean isDispatchedTasksExists = dispatchProcesses();
    boolean isReadyTaskExists = isReadyTaskExists();
    boolean isFinish = processResourceAssignments();
    checkAndAssignProcesses();
    printCurrentState();
    cleanupProcesses();
    advanceTime();
    return checkSimulationCompletion(isDispatchedTasksExists, isReadyTaskExists, isFinish);
}

ResourceManager 클래스

  • 이 클래스는 자원 할당과 안전 상태 확인을 담당
  • Banker's algorithm을 변형하여 안전한 자원 할당을 판단

주요 필드 및 메서드

  • 필드

    • available: 현재 가용 자원을 추적
    • max: 각 프로세스가 요구하는 최대 자원을 추적.
    • allocation: 각 프로세스에 할당된 자원을 추적
    • finished: 각 프로세스가 완료되었는지 여부를 추적
    • work: 현재 가용 자원의 복사본
  • 메서드

    • getProcessToAssignResources(): 현재 가용 자원 정보와 대기 중인 프로세스 정보를 기반으로 자원을 할당할 프로세스를 선택합
    • simulateRequest(): 특정 프로세스의 자원 요청을 시뮬레이션하고, 안전 상태를 확인
    • checkSafety(): 시스템의 현재 상태가 안전한지 확인합
    • canGrantRequest(): 특정 프로세스의 자원 요청을 수락할 수 있는지 확인
    • grantRequest(): 자원 요청을 수락하고 자원을 할당
    • restoreState(): 이전 상태로 복원

코드

  • getProcessToAssignResources(): 현재 가용 자원 정보와 대기 중인 프로세스 정보를 기반으로 자원을 할당할 프로세스를 선택.
    • 자원이 충분하지 않은 경우 -1을 반환하고, 할당 가능한 경우 1을 반환
public static Object[] getProcessToAssignResources(int[] currResourceInfo, int[] totalResourceInfo, List<Process> currProcessWaitingList) {
    int[] available = currResourceInfo.clone();
    int[][] max = extractMax(currProcessWaitingList);
    int[][] allocation = extractAllocation(currProcessWaitingList);

    for (int processIndex = 0; processIndex < currProcessWaitingList.size(); processIndex++) {
        int[] request = currProcessWaitingList.get(processIndex).getRemainingResources();

        if (anyGreaterThan(totalResourceInfo, request)) {
            return new Object[]{-1, null};
        }

        ResourceManager resourceManager = new ResourceManager(available, max, allocation);
        SafetyCheckResult safetyCheckResult = resourceManager.simulateRequest(processIndex, request);

        if (safetyCheckResult.isSafe()) {
            return new Object[]{1, getPickedProcesses(currProcessWaitingList, safetyCheckResult.safeSequence(), available)};
        }
    }

    return new Object[]{0, null};
}
  • simulateRequest(): 특정 프로세스의 자원 요청을 시뮬레이션하고, 시스템의 안전 상태를 확인, 안전하지 않으면 이전 상태로 복원
public SafetyCheckResult simulateRequest(int processIndex, int[] request) {
    int[] availableBackup = Arrays.copyOf(available, available.length);
    int[][] allocationBackup = copy2DArray(allocation);

    if (!canGrantRequest(processIndex, request)) {
        return new SafetyCheckResult(false, new ArrayList<>());
    }
    grantRequest(processIndex, request);
    SafetyCheckResult safetyResult = checkSafety();
    if (!safetyResult.isSafe()) {
        restoreState(availableBackup, allocationBackup);
    }
    return safetyResult;
}
  • checkSafety(): 시스템의 현재 상태가 안전한지 확인하고, 안전한 경우 안전 순서를 반환
private SafetyCheckResult checkSafety() {
    List<Integer> safeSequence = new ArrayList<>();
    boolean foundProcess;

    do {
        foundProcess = false;
        for (int i = 0; i < max.length; i++) {
            if (!finished[i] && canExecuteProcess(i)) {
                allocateResources(i);
                finished[i] = true;
                safeSequence.add(i);
                foundProcess = true;
            }
        }
    } while (foundProcess);

    return allProcessesFinished() ? new SafetyCheckResult(true, safeSequence) : new SafetyCheckResult(false, new ArrayList<>());
}


TaskScheduler 및 스케줄링 전략 설명

전략 패턴 사용

  • 전략 패턴을 사용하여 다양한 스케줄링 알고리즘을 유연하게 적용할 수 있도록 설계
  • 각 스케줄링 알고리즘은 SchedulingStrategy 인터페이스를 구현하여 서로 다른 알고리즘을 쉽게 교체하고 확장할 수 있도록 함.
  • TaskScheduler 클래스는 해당 전략을 선택하여 현재 상태에 맞는 스케줄링을 수행

TaskScheduler 클래스

  • 다양한 스케줄링 알고리즘을 적용하여 프로세스를 선택하는 역할

주요 필드 및 메서드

  • 필드

    • strategies: EnumMap을 사용하여 스케줄링 알고리즘(Enum)을 해당 전략 객체와 매핑
  • 메서드

    • getProcessIdxFromQueue(): 현재 프로세스, 준비 큐, 스케줄링 알고리즘, 현재 프로세스 실행 시간, 타임 퀀텀을 기반으로 다음에 실행할 프로세스의 인덱스를 반환. 전략 객체를 사용하여 스케줄링 알고리즘에 따라 프로세스를 선택
public static int getProcessIdxFromQueue(Process currentProcess, List<Process> readyQueue, SchedulingAlgorithm schedulingAlgorithm, int currentProcessRunTick, int timeQuantum) {
    SchedulingStrategy strategy = strategies.get(schedulingAlgorithm);
    if (strategy == null) {
        throw new IllegalArgumentException("Unsupported scheduling algorithm: " + schedulingAlgorithm);
    }
    return strategy.selectNextProcessIndex(readyQueue, currentProcess, currentProcessRunTick, timeQuantum);
}

스케줄링 전략 인터페이스

  • SchedulingStrategy 인터페이스는 다양한 스케줄링 알고리즘을 구현하기 위한 공통 인터페이스
public interface SchedulingStrategy {
    int selectNextProcessIndex(List<Process> readyQueue, Process currentProcess, int currentProcessRunTick, int timeQuantum);
}

FirstComeFirstServedStrategy 클래스

  • FCFS(First-Come, First-Served) 전략을 구현
  • 현재 프로세스가 없거나 준비 큐가 비어 있지 않으면 첫 번째 프로세스를 선택
public class FirstComeFirstServedStrategy implements SchedulingStrategy {
    @Override
    public int selectNextProcessIndex(List<Process> readyQueue, Process currentProcess, int currentProcessRunTick, int timeQuantum) {
        if (currentProcess != null || readyQueue.isEmpty()) {
            return -1;
        }
        return 0;
    }
}

RoundRobinStrategy 클래스

  • 라운드 로빈(Round Robin) 전략을 구현
  • 현재 프로세스가 없거나 현재 프로세스가 타임 퀀텀을 초과하면 준비 큐의 첫 번째 프로세스를 선택
public class RoundRobinStrategy implements SchedulingStrategy {
    @Override
    public int selectNextProcessIndex(List<Process> readyQueue, Process currentProcess, int currentProcessRunTick, int timeQuantum) {
        if ((currentProcess == null || currentProcessRunTick >= timeQuantum) && !readyQueue.isEmpty()) {
            return 0;
        }
        return -1;
    }
}

ShortestJobFirstStrategy 클래스

  • SJF(Shortest Job First) 전략을 구현
  • 비선점 알고리즘
  • 준비 큐에서 가장 짧은 실행 시간을 가진 프로세스를 선택
public class ShortestJobFirstStrategy implements SchedulingStrategy {
    @Override
    public int selectNextProcessIndex(List<Process> readyQueue, Process currentProcess, int currentProcessRunTick, int timeQuantum) {
        if (currentProcess != null || readyQueue.isEmpty()) {
            return -1;
        }
        return findShortestJobIndex(readyQueue);
    }

    private int findShortestJobIndex(List<Process> readyQueue) {
        int minIndex = -1;
        int minRemainingTime = Integer.MAX_VALUE;

        for (int i = 0; i < readyQueue.size(); i++) {
            int remainingTime = readyQueue.get(i).getRemainingTime();
            if (remainingTime < minRemainingTime) {
                minRemainingTime = remainingTime;
                minIndex = i;
            }
        }

        return minIndex;
    }
}

ShortestRemainingJobFirstStrategy 클래스

  • SRJF(Shortest Remaining Job First) 전략을 구현
  • 선점 알고리즘
  • 현재 프로세스와 준비 큐의 프로세스를 비교하여 가장 짧은 남은 시간을 가진 프로세스를 선택
public class ShortestRemainingJobFirstStrategy implements SchedulingStrategy {
    @Override
    public int selectNextProcessIndex(List<Process> readyQueue, Process currentProcess, int currentProcessRunTick, int timeQuantum) {
        if (readyQueue.isEmpty()) {
            return -1;
        }

        int minIndex = findShortestRemainingJobIndex(readyQueue);

        if (currentProcess != null && !currentProcess.isFinished()
                && currentProcess.getRemainingTime() <= readyQueue.get(minIndex).getRemainingTime()) {
            return -1;
        }

        return minIndex;
    }

    private int findShortestRemainingJobIndex(List<Process> readyQueue) {
        int minIndex = -1;
        int minRemainingTime = Integer.MAX_VALUE;

        for (int i = 0; i < readyQueue.size(); i++) {
            int remainingTime = readyQueue.get(i).getRemainingTime();
            if (remainingTime < minRemainingTime) {
                minRemainingTime = remainingTime;
                minIndex = i;
            }
        }

        return minIndex;
    }
}

시행착오


FCFS인데 왜 순서대로 실행이 안되는 것처럼 보이는거야?

  • 처음 모든 코드를 작성하고 FCFS 스케줄링으로 디버깅하는데 프로세스 순서대로 1, 2 , 3, 4 .. 순이 아니라 1, 3, 5, 6 .. 이런 식으로 순서가 진행되었었다.
  • 이유는 ? 그냥 당시에 다중 프로세서 환경에서의 자원할당 시스템에 대해서 이해도가 너무 낮았었던 것..
  • FCFS(First-Come, First-Served) 스케줄링은 프로세스가 도착한 순서대로 CPU를 할당받는 방식이지만, 이는 단순히 CPU 스케줄링에서만 고려. 즉 CPU 준비 큐에 들어있는 프로세스들을 스케줄링하는 것이고 대기상태에서는 다르다는 것!
  • 해당 시뮬레이터는 대기 상태의 프로세스들을 프로세서에 배정할 때(준비 상태로 변경할 때), "배정 가능한 = 자원 할당 가능한 프로세스 중에서" 들어온 순대로 가장 작은 통합 실행시간을 가진 프로세서에 배치되도록 했다.
  • 즉, 배정되어야할 프로세스가 현재 할당가능한 자원 이상의 자원을 필요로 할 때, 해당 자원이 사용 중이거나 충분하지 않으면, 프로세스는 먼저 도착했음에도 계속 대기 상태로 유지될 수 있다.
  • 스케줄링이 적용되는 시점은 프로세서의 준비큐에 들어가 있을때 라는 점!
  • 정리 :자원 할당의 상호 작용
    • 대기큐에서의 스케줄링 알고리즘 적용: 각 프로세서마다 별도의 대기큐를 두고, 이 대기큐에서는 스케줄링 알고리즘 원칙에 따라 프로세스를 우선적으로 선택.
    • 프로세서 배정에서의 자원 할당 고려: 실제 프로세서에 프로세스를 배정할 때는, 단순히 실행 시간만 고려하는 것이 아니라, 프로세스가 요구하는 자원을 고려해야 한다.

ex) 아래와 같은 출력 경우 (6이 7,8 보다 늦게 실행)

Generated tasks: [task number, dispatch time, expected run time, required resources]
[1, 0, 7, [0, 1, 2, 2, 1]]
[2, 0, 5, [2, 1, 2, 2, 2]]
[3, 0, 3, [1, 2, 2, 0, 2]]
[4, 1, 4, [0, 0, 1, 1, 2]]
[5, 1, 10, [2, 1, 1, 1, 0]]
[6, 1, 2, [1, 2, 1, 2, 1]]
[7, 3, 7, [1, 1, 0, 1, 0]]
[8, 5, 1, [1, 1, 1, 2, 2]]
#PROC #TICK : PROC ID     | # CPU WAIT | # WAITING QUEUE | CURRENT RESOURCES
-------------------------------------------------------------------------------
 P002  T000 :  1  2 | * *    | 3                    | [3, 3, 1, 1, 2]
 P002  T001 :  1  2 | * 1    | 3, 5, 6              | [3, 3, 0, 0, 0]
 P002  T002 :  1  2 | * 1    | 3, 5, 6              | [3, 3, 0, 0, 0]
 P002  T003 :  1  2 | * 1    | 3, 5, 6, 7           | [3, 3, 0, 0, 0]
 P002  T004 :  1  2 | * 1    | 3, 5, 6, 7           | [3, 3, 0, 0, 0]
 P002  T005 :  1  4 | 1 1    | 5, 6, 8              | [3, 1, 0, 1, 0]
 P002  T006 :  1  4 | 1 1    | 5, 6, 8              | [3, 1, 0, 1, 0]
 P002  T007 :  3  4 | 1 1    | 6, 8                 | [1, 1, 1, 2, 1]
 P002  T008 :  3  4 | 1 1    | 6, 8                 | [1, 1, 1, 2, 1]
 P002  T009 :  3  7 | 1 1    | 6                    | [0, 0, 1, 1, 1]
 P002  T010 :  5  7 | * 1    | 6                    | [1, 2, 3, 1, 3]
 P002  T011 :  5  7 | * 1    | 6                    | [1, 2, 3, 1, 3]
 P002  T012 :  5  7 | * 1    | 6                    | [1, 2, 3, 1, 3]
 P002  T013 :  5  7 | * 1    | 6                    | [1, 2, 3, 1, 3]
 P002  T014 :  5  7 | * 1    | 6                    | [1, 2, 3, 1, 3]
 P002  T015 :  5  7 | * 1    | 6                    | [1, 2, 3, 1, 3]
 P002  T016 :  5  8 | * 1    |                      | [1, 1, 2, 0, 2]
 P002  T017 :  5  6 | * *    |                      | [2, 2, 3, 2, 4]
 P002  T018 :  5  6 | * *    |                      | [2, 2, 3, 2, 4]
 P002  T019 :  5 -- | * *    |                      | [3, 4, 4, 4, 5]
 P002  T020 : -- -- | * *    |                      | [5, 5, 5, 5, 5]
Finish!

Process finished with exit code 0


자원 할당 시점의 이해

  • 운영체제에서 프로세스에게 자원을 할당해주는 시점은 일반적으로 대기(WAITING)에서 준비(READY) 상태로 변경될 때 자원을 할당한다.
  • 이 점을 이해하지 못하고 프로세스가 실행될 때 자원을 할당하려고 시도하다가 많은 시행착오를 겪었다. (끔찍했음)

+) 프로세스 생명 주기와 자원 할당

  • 프로세스 생명 주기에서 "준비 큐(Ready Queue)"에 들어간다는 것은, 해당 프로세스가 CPU를 사용할 준비가 되어 있지만 현재 CPU를 사용하고 있지 않은 상태를 의미.
  • 준비 큐에 들어간 프로세스는 CPU 할당을 기다리고 있는 상태
  • 즉 즉시 실행 가능한 친구들만 준비큐에 드가는 것
  • 자원 할당 시 상태 전이
    자원을 가용할 수 있을 때 대기 상태의 프로세스에게 자원을 할당하고, 준비 상태로 전환
    대기(WAITING) → 준비(READY):
  • CPU 할당
    CPU 스케줄러가 준비 상태의 프로세스 중 하나를 선택하여 CPU를 할당하고 실행 상태로 전환, 이 시점에는 이미 필요한 자원을 할당받은 상태.
    여기서는 CPU 스케줄러가 CPU 시간을 할당해주는 것
    준비(READY) → 실행(RUNNING):


ResourceManager의 역할

  • ResourceManager에서 안전 순서를 반환할 때 현재 자원에 할당된 만큼만 반환해주는 getProcessToAssignResources() 함수를 구현하지 않고, 단순히 안전 순서를 할당해주는 실수를 저지름.
  • 이로 인해 현재 자원이 마이너스가 되는 현상이 발생.
    • 이때 까지만 해도 위에서 겪은 자원 할당 시점때문인 줄 알았음.. (자원할당 시점 깨닫고 고쳤는데도 마이너스 돼서 멘붕)

스케줄링 알고리즘의 적용

  • 선점형과 비선점형 스케줄링 알고리즘을 구현할 때, 현재 자원이 실행되고 있는지 여부를 고려 간과 -> 스케줄링이 제대로 이루어지지 않음
  • 마찬가지로 위의 두 문제중 하난 줄 알았음.. ㅎ 참 스케줄링 알고리즘 공부하는데 이상한데 한눈 팔려서 반성 중.

ProcessSimulator의 어려움

  • ProcessSimulator 구현은 전체 배치 프로세스들이 다 실행됐는지 확인하는 것부터, 프로세스 배치, 자원 할당, 상태 전이, 스케줄링까지 다양한 요소를 고려해야 했기 때문에 매우 어려웠음
  • 그러나 이러한 과정을 통해 프로세스 스케줄링과 자원 관리에 대한 깊은 이해를 얻을 수 있었습니다.

느낀점

  • 여러 시행착오를 겪으면서 디버깅 실력이 늘 수 있었던 것 같다 ^^
  • 역시 해봐야 내가 어디가 헷갈려하는 지 알 수 있다. 내가 알고 있다 생각한 것도 확실히 하지않으면 실수를 범할 수 있음을 뼈저리게 느꼈다.
  • 아직도 개선해야할 점이 많다.
    (혹시나.. 누군가 이 글, 깃허브를 보고 수정 사항을 찾으셨다면 피드백 주시면 감사하겠습니다._.)
profile
인생 살자. (@yujeongkwon)

0개의 댓글