[인프런 워밍업 클럽 3기 - CS] - 1주차 미션 (운영체제)

[인프런 워밍업 클럽 3기 - CS] - 1주차 미션 (운영체제)

1주차 운영체제 미션

    while(true){
      wait(1); // 1초 멈춤
      bool isActivated = checkSkillActivated(); // 체크
    }
  1. 위 코드는 1초 마다 플레이어가 스킬을 사용했는지 체크하는 코드입니다. 이 방식은 폴링방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다. 이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요?

폴링방식이란 CPU가 지속적으로 장치나 하드웨어의 상태를 확인하여 변화를 확인하는 방식이다. 예제 코드의 경우 while문을 통해 1초마다 반복적으로 isActivated의 상태를 확인해주고 있다.

하나의 스킬만 확인한다면 큰 문제는 없을 수 있지만 점차 확인해야할 스킬의 수가 많아지거나, 스킬을 사용하는 객체의 수가 증가할수록 CPU는 다수의 장치를 지속적으로 확인해야 하기에 다른 중요한 작업의 처리 속도가 늦어질 수 있다. 또한 상태 확인 주기를 1초로 고정하였기 때문에 0.1초에 작업이 완료되어도 다음 다음 폴링 주기(0.9초 후)까지 사용자 응답이 지연된다는 단점이 있다.

 

해당 방식을 해결하기 위해서는 폴링 방식 대신 인터럽트로 변경해볼 수 있다. 인터럽트는 프로그램 실행 중, 특정 이벤트가 발생하면 즉시 실행은 중단하고 해당 작업을 먼저 수행하는 방식을 의미한다.

// 스킬명, 쿨타임
const SKILL = {
    Q: { name: "Q", time: 1 },
    W: { name: "W", time: 2 },
    E: { name: "E", time: 3 },
    R: { name: "R", time: 4 },
};
// 스킬 사용 상태 확인
const skillState = Object.values(SKILL).reduce((acc, skill) => {
    acc[skill.name] = { isActive: false, lastUsed: 0 };
    return acc;
}, {});

document.addEventListener("keydown", (event) => {
    const inputKey = event.key.toUpperCase();
    const skill = skillState?.[inputKey];
    const now = Date.now();

    if (!skill) return;
    if (!checkSkillActivated(skill)) return;

    // 현재 - 마지막 스킬 사용 시간이 쿨타임보다 적다면 사용 가능
    if (now - skill.lastUsed >= skill.time * 1000) {
        skill.isActive = true;
        skill.lastUsed = now;

        // 쿨타임 이후, 스킬 활성화 false
        setTimeout(() => {
            skill.isActive = false;
        }, SKILL[inputKey].time * 1000);
    }
});

const checkSkillActivated = (skill) => {
    if (!skillState?.[skill]) return false;

    return skillState[skill].isActive;
};

기존에는 스킬을 1초마다 체크하게 확인 하였다면

작성된 코드에서는 스킬을 사용할 때만 스킬을 체크하도록 수정하였다.

 

이벤트 리스너를 통해서 키 입력을 받으면

  1. 해당 스킬이 존재하는지.

  2. 스킬을 사용할 수 있는지 체크

하여 스킬을 발동시키고 쿨타임과 스킬 사용 활성화를 true로 설정하였다.

setTimeout을 통해 스킬의 쿨타임 뒤에 스킬 사용 활성화를 false로 변경해주었다.

 

  1. 프로그램과 프로세스가 어떻게 다른가요?

프로그램이란 저장장치에 저장된 명령문의 집합체이며 프로세스는 실제 실행 중인 프로그램을 의미한다.

프로그램은 실행하기 전까지 저장장치에 저장만 되어 있는 수동적인 존재이지만 프로세스는 실행되면 .exe 파일이 실행되어 메모리에 코드, 데이터, 스택, 힙 영역 등에 올라가며 CPU 연산과 I/O를 사용하는 능동적인 존재이다.

 

  1. 멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요?

멀티프로그래밍이이란 메모리에 여러 개의 프로세스를 올려 하나의 CPU 작업을 수행하는 것을 의미한다. I/O 작업으로 해당 프로세스에서 CPU가 연산을 수행하지 못한다면 대기하지 않고 다른 프로세스에 할당되어 사용된다.

멀티프로세싱이란 여러 개의 CPU로 다수의 프로세스 작업들을 동시에 수행하는 것을 의미한다.

 

  1. 운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요?

PCB(Process Control Block)을 통해 프로세스를 관리한다. PCB에는 포인터 구조, 프로세스 상태, PID, 프로그램 카운터, 레지스터 정보 등 프로세스에 필요한 다양한 정보들을 담고 있으며 운영체제는 PCB를 통해 상태를 조회하고 컨텍스트 스위칭을 실행할 수 있다.

PCB 정보

포인터 구조 : 부모, 자식 프로세스에 대한 포인터(주소) 저장

프로세스 상태: 프로세스의 현재 상태를 저장(생성, 준비, 대기, 실행, 완료)

PID: 프로세스 식별 ID 저장

프로그램 카운터: 다음에 실행되어야 할 명령어 위치 저장

레지스터 정보: 프로세스 실행될 때, CPU에 저장되었던 레지스터 정보 저장

 

  1. 컨텍스트 스위칭이란 뭔가요?

프로세스가 실행 중인 상태에서 다른 프로세스를 실행하기 위해 실행 중인 프로세스 상태를 저장하고 다른 프로세스로 교체하는 것을 의미한다. 운영체제에 의해 실행 중인 PCB의 내용이 수정되고, 교체될 PCB의 내용이 CPU에 세팅된다.

 

컨텍스트 스위칭 과정

1. 프로세스 A의 CPU 점유 시간 초과

2. 인터럽트 발생

3. CPU의 레지스터 값 등을 PCB A에 저장

4. PCB B를 참조해서 이전 프로세스 B의 작업을 이어감

- 프로그램 카운터(다음에 실행될 명령어 주소)를 통해 이어서 명령어 실행 가능

5. 프로세스 B의 CPU 점유 시간 초과

6. 인터럽트 발생

7. CPU의 레지스터 값 등을 PCB B에 저장

 

📒 회고

이번 주말은 여러 일정이 겹쳐있어서 미션을 수행할 시간이 많이 부족했뿐만 아니라, 생각보다 미션이 오래 걸렸던 것 같다.

다음 주 부터는 미리미리 강의 정리하면서 발자국도 함께 작성하는 것이 중요할 것 같고 미션도 올라오는 대로 바로 시작해야

안정적으로 미션을 제출할 수 있을 것 같다.

 

추가로 스터디에서 사람이랑 미션에 대해서도 얘기해보며 집단 지성을 이용해서 조금 더 획기적인 아이디어들을

토론하고 고민해보는 것도 좋은 생각일 것 같다!

댓글을 작성해보세요.

채널톡 아이콘