드디어 기대하던 Pintos 학습 주차에 들어섰다. Jungle에 입소하기 전부터 가장 기대하던 파트였던 만큼 설렘과 동시에 부담도 느껴졌다. OS의 동작 원리를 직접 이해하고, 그 로직을 스스로 구현해볼 수 있는 기회는 흔치 않기 때문에 더욱 의미 있게 다가왔다. 앞으로 4주 동안은 깊이 있는 학습에 집중하겠다는 다짐을 했고, 특히 개념을 제대로 체화하기 위해 AI는 학습 보조 용도로만 제한적으로 활용하기로 했다.
비록 힘든 과정이겠지만 나중에 돌이켜봤을때 의미있던 경험으로 남을 수 있도록 노력하자!
핵심 역량 평가
| 역량 | 달성도 | 목표 |
| 문제해결 | 90% | alarm clock, priority scheduling, priority donation의 핵심 문제를 정확히 정의하고, 최소한 priority-donate 테스트까지 통과할 수 있도록 구현한다. |
| mlfqs, priority-donate-lower, priority-donate-sema 테스트를 제외한 모든 테스트 케이스를 통과했다. | ||
| 설계 | 0% | 이후 Project 2~4에서도 구조를 크게 바꾸지 않도록, 확장성을 고려하여 설계한다. |
| 다음 주차부터 하는 내용을 아직 알지 못해, 이를 고려하며 구현을 하는 것은 무리가 있었다. | ||
| 구현 | 100% | Pintos의 기존 코드 흐름을 해치지 않으면서 테스트케이스가 통과되도록 구현한다. |
| 기존 코드 구조를 해치지 않고, 알맞게 로직을 수정/추가 하였다. | ||
| 품질 | 100% | 특정 로직을 수정할때마다 Project 1 테스트 케이스를 전부 반복 실행하며 실패 원인을 분석하고 수정하여 안정성을 높인다. |
| 꾸준히 테스트를 진행하여, 이전에 통과되다가 갑자기 fail이 뜨는 테스트 케이스를 잡아낼 수 있었다. | ||
| 유지보수 | 70% | 복잡한 로직은 함수로 분리하고, 코드 의도를 짧은 주석으로 남겨 팀원이 이해하기 쉽게 작성한다. |
| thread_yield 로직을 모듈화 한 것이 아니라 필요한 자리마다 복사 붙혀넣기 하다 보니까 코드가 더러워진 부분이 존재한다. | ||
| 협업 | 80% | 팀원들이 같은 파일을 수정하더라도 충돌을 줄일 수 있도록 구현 범위를 나누고, PR/커밋 단위로 변경 이유와 테스트 결과를 공유한다. |
| 과제 특성상 모두의 코드를 merge하는 건 불가능했기 때문에 내 코드로 merge를 진행하였다. 대신 대 코드에 대해 전부 설명하는 시간을 가졌다. | ||
| 태도 | 100% | 테스트 실패를 단순 오류로 넘기지 않고, Pintos 내부 동작 원인을 끝까지 추적하며 해결하는 집요함을 기른다. |
| sema_up 로직으로 인해 발생한 TIMEOUT 문제가 터지는 지점을 찾아내기 위해 gdb를 사용해서 끝까지 추적하였다. | ||
| AI 활용 | 80% | AI를 단순 코드 생성 도구가 아니라, Pintos 개념 이해, 테스트 실패 원인 분석, 디버깅 방향 설정, 코드 리뷰 보조 도구로 활용하여 생산성을 높인다. |
| 코드를 직접 생성하는 일은 없도록 하였고, 개념 이해, 테스트 실패 원인 추적, 디버깅 방법 등에만 활용하였다. | ||
| 학습 민첩성 | 100% | 스레드, 인터럽트, 세마포어, 락, condition variable, priority donation 같은 낯선 OS 개념을 빠르게 이해하고 구현에 즉시 적용한다. |
| Pintos의 모든 개념을 이해하려 하지 않고, 핵심 부분만 학습하고 바로 구현에 뛰어들었다. | ||
Weekly Problem : sema_up() 메서드에서의 value++ 호출 순서에 따른 오류 발생
팀 발표에서 다루었던 문제이지만, 블로그에 다시 정리해두려고 한다.
코드 한 줄의 위치때문에 모든 테스트 케이스가 TIMEOUT이 뜨는 것을 보며 설계의 중요성에 대해 다시금 깨닫게 되었다.
sema_up()의 기존 코드 로직을 살펴보자.

우선순위가 높은 thread를 unblock하고, thread_yield 로직을 수행한다.
그리고 제일 나중에 sema->value++을 수행한다.
이렇게 코드를 짰을 때 갑자기 거의 모든 테스트 케이스에서 TIMEOUT이 뜨는 문제가 발생했다.
나는 처음에 priority-sema 테스트를 예시로 로직의 문제점을 찾아내려고 했다.
그래서 내린 결론은 다음과 같다.

이 테스트케이스는 메인 스레드에서 10개의 자식스레드를 만들고 시작한다.
자식스레드는 모두 sema_down으로 잠들게 되고, 마지막에 메인 스레드에서 sema_up을 통해 잠든 스레드를 하나씩 깨운다.
여기서 value++의 위치에 따라 문제가 발생한다.

메인 스레드에서 sema_up을 호출하면
1. 자식스레드 하나를 unblock 하고,
2. thread_yield를 수행한다.
그러면 자식스레드는 sema_down 메서드 내에서 Blocked되었던 위치에서 깨어나고, 다시 while문의 조건문을 재검사하게 된다.
원래 정상 로직에서는 sema_up을 하면 sema->value를 1만큼 증가시키고 스레드가 깨어나야 한다.
그런데 현재 코드에서는 아직 sema->value를 증가시키지 않았기 때문에, while문을 빠져나가지 못하고 메인 스레드가 다시 block되게 된다.
메인 스레드가 block됨에 따라서 다시 자식스레드의 sema_up의 thread_yield쪽으로 돌아오게 되고, 그제서야 sema->value++가 수행된다. 이후의 로직은 정상적으로 작동할 것이다. 왜냐하면 이제는 value가 1이기 때문에 sema_up을 호출했을때 sema_down에서 정상적으로 while문을 벗어날 수 있을 것이기 때문이다.
하지만 이미 첫번째 sema_up이 무시됨에 따라 10개의 스레드가 깨어난 것이 아니라 9개의 스레드만 깨어나게 된다!
➡️ 따라서 마지막 남은 스레드가 영원히 blocked되어 TIMEOUT이 뜨는 것이다!
...라고 생각했었다.
실제 테스트케이스의 결과

그냥 result 파일에 적혀있는 TIMEOUT만 보고 넘어가서 정확한 문제상황을 파악하지 못했던 것 같다.
실제 테스트 결과인 output파일을 보니 내가 생각한 것과 다른 출력이 있었다.
9개의 스레드는 깨어나면서 msg를 출력했을 줄 알았는데, 그냥 부팅이 진행됨과 동시에 TIMEOUT이 뜬 것이다.
뭔가 잘못되었음을 깨닫고 디버깅을 통해 실제로 터지는 부분이 어딘지 찾아보기로 했다.
Debugging 결과

sema_up 메서드에 대해 브레이크를 설정하고 테스트케이스를 돌려보았다.
처음 멈춘 구간에서 bt(backtrace) 명령어로 call stack을 출력해보았는데, OS를 부팅할 때 idle 스레드를 만드는 부분에서 sema_up 함수가 호출되었다.
이 후 계속 진행하기 위해 continue를 했는데... 갑자기 무한 Continuing이 발생했다.
Ctrl + c로 진행을 중단하고 info threads 명령어로 현재 스레드 정보를 확인해보았는데
메인 스레드가 죽고, idle 스레드만 남아있었다.
그래서 idle 함수가 호출되는 thread_start() 메서드부터 흐름을 추적해보았다.
thread_start()와 idle 스레드

thread_start 메서드 (메인 스레드)
thread_start()는 스레드 스케줄러를 시작하는 함수이다. 크게 3가지 일을 수행한다.
1️⃣ idle 스레드를 생성한다.
2️⃣ 인터럽트를 활성화한다.
3️⃣ sema_down으로 blocked되고, idle 스레드의 초기화를 기다린다.
idle 메서드 (idle 스레드)
1️⃣ 전역 변수인 idle_started에 자기 자신을 등록한다.
2️⃣ sema_up으로 메인 스레드를 다시 깨운다.
3️⃣ 이 후, blocked 되면서 ready_list가 빌 때마다 스케줄러에 의해 다시 선택되어 깨어난다.
여기서 idle 메서드에서 blocked된 메인 스레드를 깨우는 부분에서, 위에서 설명한 문제가 발생한다.
value를 나중에 증가시키기 때문에 메인 스레드의 sema_down에서 while 반복문을 탈출하지 못하고,
메인스레드가 영원히 잠들게 된다!
해결 방안

이를 해결하는 법은 매우 간단하다.
그냥 thread_yield가 호출되기 전에 value를 1만큼 증가시켜주면 되는 것이다.
이렇게 되면 스레드 unblock 후 yield를 했을 때, value가 1이기 때문에 while 조건문을 무사히 탈출할 수 있다.
Week9 회고
프로젝트 마무리를 하고, 유윤선 코치님의 말씀을 듣고 프로젝트 진행 방식에 대해 고민해보게 되었다.
한 주 동안 merge 없이, 개인의 레포에서 구현을 진행했던 팀에 관한 피드백이 주를 이루었다.
Pintos 특성상 특정 파일을 계속해서 수정해야되기 때문에 분업이 사실상 불가능하고, 이 때문에 브랜치 관리에 소홀했던 것은 우리팀도 마찬가지였다. 물론 중간에 가장 진행도가 높은 코드를 master branch에 merge 하고, 4명이서 같은 코드에서 다시 시작하는 과정을 겪긴 했다. 하지만 이렇게 되면 다른 사람들의 코드는 보지도 못한채로 사라지게 되고, 학습 수준이 느린 사람들은 이 속도를 따라가기 버거울 수도 있다는 것을 다시금 생각하게 되었다.
그래서 다음주부터는 비록 구현 속도가 느리더라도, 팀원들과 함께 나아가는 방향을 고려해보려고 한다. 각자의 코드를 띄워두고 치열하게 싸우며 conflict도 내보고, 각 코드의 장점들을 선택하여 merge하며 팀원들과 함께 성장하는 주차가 되었으면 한다.
'크래프톤 JUNGLE' 카테고리의 다른 글
| [Week10] WIL - Pintos_Project 2 (0) | 2026.05.08 |
|---|---|
| [Week8] WIL - 네트워크에 발 담그기 (1) | 2026.04.23 |
| [Week7] WIL - 무한 코어타임 지옥 (2) | 2026.04.16 |
| [Week6] WIL - Hello C World! (0) | 2026.04.09 |
| [Week5] WIL - DP 알고리즘 부수기 (0) | 2026.04.02 |