크래프톤 정글/TIl _ WILL

크래프톤 정글 · Week 9 WIL · Pintos Project 1 Threads

cedis 2026. 4. 30. 02:34

 

크래프톤 정글 · Week 9 WIL · Pintos Project 1 Threads

Pintos, 완성된 교향곡에서 베이스를 찾는 과정

9주차가 끝났고, 내 손에는 Pintos 글 3편과 로드맵, 테스트 기반 구현 가이드가 남았다.

숫자보다 중요한 건 그 과정에서 내가 운영체제 코드를 읽는 방식이 바뀌었다는 점이다.

이번 주를 한 줄로 정리하면

이번 Pintos 프로젝트는 완성된 교향곡 속에서 흐름을 이해하기 위해 베이스를 찾아가는 과정이었다.

처음에는 모든 파일과 함수가 동시에 울리는 것 같았다. 어느 함수가 주선율인지, 어떤 interrupt가 박자를 잡는지, 어떤 테스트가 낮게 깔린 베이스처럼 전체 흐름을 붙들고 있는지 보이지 않았다. 이번 주는 그 소음을 한 줄씩 분리해서 듣는 시간이었다.

이번 주 목표 3가지

✅ 목표 1. Pintos Project 1 Threads의 큰 흐름을 이해한다.

✅ 목표 2. 테스트 케이스를 요구사항처럼 읽고, 실패 원인을 기능 단위로 좁힌다.

✅ 목표 3. 팀원이 다시 볼 수 있는 학습 문서와 블로그 글로 남긴다.

세 가지 모두 어느 정도 달성했다. 다만 달성의 의미는 각각 달랐다. 목표 1은 운영체제 전체를 이해했다는 뜻이 아니라, Alarm → Priority Scheduler → Donation → MLFQS로 이어지는 흐름의 뼈대를 잡았다는 뜻이다. 목표 2는 테스트를 단순 채점기가 아니라 문제 설명으로 읽기 시작했다는 뜻이고, 목표 3은 내가 이해한 것을 팀과 미래의 내가 다시 볼 수 있는 형태로 바꾸려 했다는 뜻이다.

이번 주 흐름 지도

이번 주의 Pintos 학습은 네 개의 악장이 이어지는 구조로 보였다. 각 단계는 따로 떨어진 과제가 아니라, “thread가 언제 CPU를 받을 것인가”라는 질문을 조금씩 확장했다.

1악장 · Alarm

잠든 thread를 언제 다시 무대로 올릴 것인가

2악장 · Priority

READY가 된 thread 중 누가 먼저 연주할 것인가

3악장 · Donation

높은 priority가 lock에 막혔을 때 흐름을 어떻게 살릴 것인가

4악장 · MLFQS

과거 CPU 사용 기록으로 priority를 자동 조율할 것인가

이 흐름을 잡고 나서야 테스트 케이스가 흩어진 문제가 아니라 하나의 악보처럼 보이기 시작했다. Alarm은 박자, Priority는 연주 순서, Donation은 막힌 파트의 임시 보강, MLFQS는 자동 조율에 가까웠다.

이번 주에 한 일 체크리스트

이번 주 작업은 “Pintos를 공부했다”로 끝내기에는 너무 넓었다. 실제로 손에 남은 것을 기준으로 정리하면 다음과 같다.

☑ Project 1 학습 로드맵 작성
금, 토, 월, 화, 수 흐름을 Alarm, Priority, Donation, MLFQS 순서로 나누고 요일별 체크리스트를 붙였다.

☑ 테스트 케이스 기준 체크리스트 보강
alarm-priority, priority-donate-one, mlfqs-load-avg처럼 테스트 이름이 묻는 질문을 기능별로 다시 정리했다.

☑ 파일명 기준 작업 지도 작성
테스트가 실패했을 때 아무 파일이나 열지 않도록, timer, thread, synch 계열 파일이 각각 어떤 책임을 갖는지 정리했다.

☑ 개념학습과 테스트 기반 구현 가이드 작성
처음부터 1000줄을 이해하려 하기보다, 테스트 하나가 요구하는 10줄씩을 이해하는 방식으로 접근했다.

☑ Pintos 기술 글 3편 작성
1편은 Alarm과 alarm-priority, 2편은 Priority Scheduler와 Donation, 3편은 MLFQS를 다뤘다.

☑ MLFQS 테스트 통과 흐름 정리
검증용 복사본 기준으로 MLFQS 9개 테스트 PASS와 기존 alarm-*, priority-* 회귀 확인을 글의 근거로 남겼다.

☑ 오케스트라 비유로 발표와 회고의 중심 문장 정리
“완성된 교향곡에서 베이스를 찾는 과정”이라는 문장으로 이번 주의 기술 학습과 개인 회고를 묶었다.

핵심 역량별 WIL

10대 역량은 표 하나로 끝내면 너무 가볍게 지나간다. 그래서 이번 주에는 각 역량을 카드처럼 분리하고, 실제로 겪은 장면과 지난주 대비 변화, 다음에 가져갈 원칙을 따로 적었다.

1. 문제해결

정의

문제를 정의하고 논리적으로 해결하는 능력

지난주 대비

요청 흐름 추적에서 커널 상태 전이 추적으로 확장

가져갈 것

실패 테스트 이름을 먼저 해석하고, 기능 범위를 나눈다.

이번 주 가장 큰 문제는 “Pintos를 모른다”가 아니었다. 진짜 문제는 어디가 막힌 것인지 모르는 상태였다. 처음에는 alarm-priority가 Alarm Clock 테스트라고만 생각했다. 그런데 들여다보니 이 테스트는 잠든 thread를 깨우는 것만 묻지 않았다. 깨어난 thread가 ready list에 들어간 뒤, priority 순서로 실행되는지도 함께 묻고 있었다.

이때 문제를 보는 방식이 바뀌었다. 테스트 이름은 제목이고, 기대 출력은 채점 기준이며, 실패 로그는 어느 마디에서 박자가 어긋났는지 알려주는 표시였다. 백준 문제를 풀 때 입력 조건을 읽듯이, Pintos 테스트를 읽어야 했다.

2. 설계

정의

효율적이고 확장 가능한 구조를 기획하는 능력

지난주 대비

요청 파이프라인 이해에서 커널 흐름 설계로 이동

가져갈 것

코드보다 흐름을 먼저 설계하고, 기능과 책임 파일로 나눈다.

이번 주 초반에는 코드를 위에서부터 읽으면 언젠가 이해될 거라고 생각했다. 하지만 Pintos는 한 함수 안에서 시작과 끝이 닫히는 코드가 아니었다. timer interrupt가 들어오고, thread가 BLOCKED가 되고, 다른 thread가 READY가 되고, scheduler가 다시 RUNNING을 고르는 식으로 흐름이 여러 파일에 흩어져 있었다.

그래서 학습 구조를 먼저 설계했다. Alarm Clock은 박자, Priority Scheduler는 연주 순서, Donation은 막힌 파트를 임시로 살리는 장치, MLFQS는 연주자의 과거 행동을 보고 자동으로 배치를 바꾸는 방식으로 잡았다. 오케스트라 비유는 예쁘게 보이기 위한 장식이 아니라, 내가 복잡한 OS 흐름을 분리해서 듣기 위한 도구였다.

3. 구현

정의

설계한 내용을 실제 동작하는 코드로 작성하는 능력

지난주 대비

애플리케이션 코드에서 커널 코드 정책 변화로 확장

가져갈 것

최소 수정은 적게 고치는 것이 아니라 정확한 정책 지점을 고치는 것이다.

구현에서 가장 인상 깊었던 장면은 작은 코드 변화가 스케줄러의 정책을 바꾸는 순간이었다. ready list에 thread를 그냥 뒤에 붙이면 FIFO에 가깝게 동작한다. 하지만 priority scheduler에서는 READY가 된 thread가 무조건 줄 뒤에 서면 안 된다.

/* before */
list_push_back (&ready_list, &t->elem);

/* after */
list_insert_ordered (&ready_list, &t->elem,
        thread_priority_more, NULL);

바뀐 건 한 줄처럼 보이지만 의미는 컸다. “먼저 온 thread가 먼저 실행된다”에서 “더 중요한 thread가 먼저 실행된다”로 정책이 바뀐 것이다. 구현은 결국 코드를 많이 쓰는 일이 아니라, 어떤 줄이 어떤 정책을 바꾸는지 아는 일이었다.

4. 품질

정의

버그 없는 안정적인 코드와 테스트를 만드는 능력

지난주 대비

동작 확인에서 테스트군 검증과 회귀 확인으로 발전

가져갈 것

테스트 하나의 PASS가 전체 품질을 보장하지 않는다.

이번 주에는 테스트가 품질의 언어였다. priority-donate-one이 통과한다고 donation이 끝난 것이 아니었다. multiple donation, nested donation, donation 회수까지 통과해야 lock을 둘러싼 priority inversion을 제대로 다뤘다고 말할 수 있었다.

MLFQS도 마찬가지였다. 공식만 맞는다고 되는 것이 아니었다. 매 tick, 매 4 tick, 매 1초라는 갱신 타이밍이 맞아야 했다. 검증용 복사본 기준으로 MLFQS 9개 테스트를 PASS로 확인하고, 기존 alarm-*, priority-* 회귀까지 확인한 이유가 여기에 있다.

5. 유지보수

정의

읽기 좋고 수정하기 쉬운 코드와 문서를 남기는 능력

지난주 대비

개인 기록에서 재사용 가능한 팀 가이드로 확장

가져갈 것

문서는 다시 실행 가능한 기억을 만드는 일이다.

이번 주에 남긴 문서의 목적은 “보기 좋은 정리”가 아니었다. 나중에 다시 Pintos를 열었을 때, 내가 어디서부터 봐야 하는지 잊지 않기 위한 지도였다. 그래서 파일명 기준 작업 지도와 테스트 기반 구현 가이드를 따로 만들었다.

특히 코드 블록을 설명할 때는 수정 전과 수정 후를 나란히 놓으려고 했다. 어떤 코드가 바뀌었는지보다, 그 결과 어떤 동작이 바뀌었는지가 더 중요했다. 설명이 유지보수의 일부라는 것을 이번 주에 다시 느꼈다.

6. 협업

정의

팀원과 기준을 맞추고 시너지를 내는 과정

지난주 대비

개인 이해에서 팀이 공유할 테스트/파일 기준으로 확장

가져갈 것

협업은 코드를 합치는 일보다 기준을 맞추는 일이다.

이번 주 과제는 개인 코드가 아니라 팀의 최종 결과물이 중요했다. 그래서 내가 작성한 로드맵과 파일명 기준 지도는 개인 공부용이면서 동시에 팀이 같은 기준을 공유하기 위한 자료였다. 같은 테스트를 보고도 각자 다른 파일을 고치기 시작하면 병합은 금방 어려워진다.

PR을 설명할 때도 단순히 “테스트 통과합니다”로는 부족하다고 느꼈다. 어떤 invariant를 지키는지, 예를 들어 ready list는 priority 순서를 유지해야 한다거나, lock release 후 donation이 회수되어야 한다는 식의 문장이 필요했다.

7. 태도

정의

자기주도 학습과 과제에 대한 몰입, 집요함

지난주 대비

디버깅 집요함에서 요구사항으로 돌아가는 집요함으로 발전

가져갈 것

모르면 멈추지 말고 더 작은 흐름으로 쪼갠다.

이번 주는 “모르는 상태”를 오래 견뎌야 했다. Pintos는 처음부터 친절하게 다가오지 않았다. 내가 알고 있는 C 문법과 자료구조 지식만으로는 부족했고, interrupt, scheduler, synchronization이 서로 엮이는 흐름을 계속 다시 봐야 했다.

특히 중간에 AI가 내가 요청한 범위보다 좁은 단일 donation 코드로 방향을 잡았을 때, 그대로 받아들이면 안 된다는 것도 배웠다. 내가 원하는 목표는 “표 하나를 해결하는 코드”가 아니라 “깃북 기본 스케줄러 요구사항을 만족하는 코드”였다. 그 차이를 다시 짚고 바로잡은 것도 이번 주 태도 중 하나였다.

8. 비즈니스 이해

정의

서비스 가치와 사용자 입장을 고려하는 시각

지난주 대비

서버 기능 관점에서 시스템 정책과 응답성 관점으로 확장

가져갈 것

시스템 정책은 사용자 경험과 분리되어 있지 않다.

운영체제 과제에서 비즈니스 이해를 말하는 것은 조금 멀게 느껴졌다. 하지만 MLFQS를 보면서 연결점이 생겼다. 스케줄러는 단순히 CPU를 공평하게 나누는 장치가 아니라, 사용자가 느끼는 반응성과도 연결된다.

CPU를 오래 쓰는 작업과 짧게 반응해야 하는 작업을 같은 방식으로 다루면 시스템은 답답해진다. MLFQS는 최근 CPU 사용량과 nice, load average를 보고 priority를 계속 다시 계산한다. 결국 “누가 CPU를 받을 것인가”는 내부 구현 문제이면서 동시에 사용자가 느끼는 시스템 반응성의 문제였다.

9. AI 활용

정의

AI 도구로 생산성을 높이고 결과를 검증하는 능력

지난주 대비

구현 보조에서 학습 구조화와 비판적 검증으로 확장

가져갈 것

AI에게 맡기기 전에 목표와 범위를 먼저 선명하게 적는다.

이번 주 AI는 빠른 정리 도구이면서 동시에 조심해야 할 도구였다. 로드맵, 코드 블록, 테스트 매핑, 블로그 글, 발표 대본을 만드는 데 AI를 적극적으로 썼다. 하지만 AI가 항상 내가 원하는 문제 범위를 정확히 잡아주는 것은 아니었다.

특히 “최소 수정”이라는 말을 AI가 너무 좁게 해석해서 단일 donation 수준으로 답을 준 적이 있었다. 내가 원한 것은 깃북 기준 기본 스케줄러 전체였다. 그때 깨달은 건 명확하다.

AI는 속도를 올려주지만, 목표 범위는 내가 잡아야 한다.

10. 학습 민첩성

정의

새로운 기술과 개념을 빠르게 습득하는 능력

지난주 대비

네트워크 흐름에서 OS 정책과 수식 이해로 확장

가져갈 것

새 개념은 이름보다 존재 이유를 먼저 묻는다.

이번 주에는 threads, synchronization, priority donation, MLFQS를 한 주 안에 만났다. 각각 따로 보면 개념이지만, Pintos에서는 모두 코드와 테스트로 연결되어 있었다. 특히 MLFQS는 처음에는 수식 덩어리처럼 보였지만, 질문을 바꾸니 조금 이해됐다.

“이 공식을 외워야 하나?”가 아니라 “왜 최근 CPU를 많이 쓴 thread의 priority를 낮춰야 하나?”라고 물으니 방향이 보였다. 외우는 대신 설계 이유를 묻는 방식이 이번 주에도 통했다.

이번 주 학습 정리

Pintos Project 1 흐름

구간 내가 이해한 질문 대표 테스트
Alarm Clock thread를 busy waiting 없이 재웠다가 정확한 tick에 깨울 수 있는가 alarm-single, alarm-priority
Priority Scheduler READY 상태가 된 thread 중 누가 먼저 CPU를 받아야 하는가 priority-preempt, priority-sema
Priority Donation 높은 priority thread가 낮은 priority lock holder를 기다릴 때 priority inversion을 줄일 수 있는가 priority-donate-one, priority-donate-chain
MLFQS 사용자가 정한 priority가 아니라 recent_cpu, nice, load_avg로 priority를 자동 계산할 수 있는가 mlfqs-load-avg, mlfqs-recent-1

이번 주 산출물

☑ 학습 로드맵과 요일별 체크리스트

☑ 파일명 기준 작업 지도

☑ 개념학습과 테스트 기반 구현 가이드

☑ Pintos Tistory 글 1편, 2편, 3편

☑ Week 9 WIL 작성본과 오케스트라 발표 대본

이번 주에 내가 조금 성장했다고 느낀 지점

예전 같으면 Pintos를 열고 “운영체제 어렵다”에서 멈췄을 것 같다. 이번 주에는 적어도 그렇게 멈추지는 않았다. 막히면 테스트 이름으로 돌아갔고, 테스트가 묻는 상태 전이를 다시 봤고, 그 상태 전이를 만드는 코드 조각을 찾았다.

완성된 교향곡에서 처음부터 모든 악기를 구분할 수는 없었다. 하지만 베이스를 찾으면 곡이 조금씩 들리기 시작한다. 이번 주의 베이스는 테스트 케이스와 interrupt였다. 그것을 붙잡고 나니 Pintos가 완전히 이해되지는 않았지만, 적어도 다시 들어갈 입구는 생겼다.

한눈에 보는 성장 요약

핵심역량 이번 주 성장 포인트 지난주 대비
문제해결 테스트 이름을 요구사항처럼 읽음 요청 흐름 추적에서 커널 상태 전이 추적으로 확장
설계 Alarm → Priority → Donation → MLFQS 학습 구조 설계 단일 실습 흐름 정리에서 팀 학습 구조 설계로 발전
구현 작은 코드 변경이 정책을 바꾸는 지점 이해 애플리케이션 코드에서 커널 코드로 이동
품질 MLFQS 9개 테스트와 기존 테스트 회귀 확인 동작 확인에서 테스트군 검증으로 발전
유지보수 파일명 지도와 전후 동작 설명 작성 개인 기록에서 재사용 가능한 가이드로 발전
협업 팀이 같은 테스트와 책임 파일을 보도록 문서화 개인 이해에서 팀 기준 공유로 확장
태도 모르는 상태를 테스트 단위로 쪼개며 버팀 디버깅 집요함에서 요구사항으로 돌아가는 집요함으로 발전
비즈니스 이해 스케줄러 정책과 사용자 반응성 연결 서버 기능 관점에서 시스템 정책 관점으로 확장
AI 활용 AI 답변을 요구사항과 테스트로 검증 구현 보조에서 학습 구조와 비판적 검증으로 확장
학습 민첩성 MLFQS까지 한 주 안에 큰 그림 확보 네트워크 흐름 이해에서 OS 정책 이해로 확장

다음 주 목표와 학습 키워드

다음 주 목표

  • Pintos 다음 프로젝트에서도 테스트 이름을 문제 설명처럼 읽는 방식을 유지한다.
  • PR을 작성할 때 통과한 테스트뿐 아니라 지켜야 하는 invariant를 함께 적는다.
  • MLFQS처럼 수식과 코드가 만나는 부분은 테스트 하나를 손으로 계산해 납득한다.

학습 키워드

user program, system call, address validation, process control, file descriptor, page table, test-driven debugging

마무리하며

Pintos 글 3편을 썼고, 로드맵과 구현 가이드를 만들었다.

숫자보다 더 기억에 남는 건, 처음에 전부 소음처럼 들리던 코드에서 베이스를 하나씩 찾아낸 순간들이다.

다음 주도 먼저 박자를 찾고, 그다음 코드를 읽겠다.