PintOS| project1 : thread | 스레드를 직접 다뤄보다.

맹쥐·2025년 5월 20일
6

kaist - PintOS

목록 보기
6/10

컴퓨터는 수많은 코드의 흐름으로 돌아간다.
이 코드 흐름 하나하나를 우리는 스레드(Thread)라고 부른다.
정확히 말하면,
CPU가 명령어를 순서대로 실행해나가는 경로(흐름)이다.


예를 들어보자.

print("동생 깨우기")
print("세수하기")
print("아침 먹기")

이 코드는 아침에 일어나서 행동하는 순서를 나타낸 것이다.
이렇게 순서대로 처리되는 흐름이 바로 하나의 스레드이다.

print("노래 재생")
print("다음 곡 준비")

이건 음악을 재생하는 코드이다.
만약 컴퓨터가 아침 루틴과 노래 재생을 동시에 처리한다면?

  • 아침 루틴 스레드
  • 음악 재생 스레드

→ 이렇게 서로 다른 일을 하는 두 개의 스레드가 있는 것이다.


🧵 PintOS | 스레드를 직접 다뤄보다

PintOS Project 1에서는
이 스레드라는 실행 흐름을 직접 만들어보고,
그 흐름을 운영체제가 어떻게 관리하는지 구현해보는 프로젝트이다.


누가 스레드를 관리할까?

컴퓨터에는 실행해야 할 코드들이 정말 많다.
즉, 수많은 스레드들이 존재한다.

PintOS에서는 CPU가 단 하나만 있다고 가정한다.
한 번에 딱 하나의 스레드만 실행할 수 있다.

나머지 스레드들은 기다려야 한다.
줄을 서서 "내 차례야!"라고 외치고 있는 셈이다.

누가 그 줄을 세워주고, 차례를 정해줄까?

바로 운영체제다.
운영체제는 마치 감독 선생님😎처럼 스레드들을 관리한다.


OS의 주요 역할 : 스케줄링 (Scheduling)

역할설명
스레드 만들기새로운 스레드를 생성하고 대기 목록에 넣음
스케줄링누가 CPU를 사용할지 결정
양보 처리실행 중인 스레드가 자발적으로 CPU를 내놓음
멈추기스레드가 자원 기다릴 때 잠시 대기시킴
깨우기자원이 생기면 다시 줄 세움

이 과정을 한마디로 부르면?
스케줄링(Scheduling)이다.


스레드는 어떤 정보로 구성될까?

운영체제가 스레드를 관리하기 위해
스레드를 한 구조체(struct)로 정의해 놓았다.

이 구조체에는 다양한 정보가 담겨 있지만,
스케줄링 관점에서 특히 중요한 두 가지는 아래와 같다.

  • status: 지금 스레드가 어떤 상태에 있는지 나타냄 (예: 실행 중, 대기 중 등)
  • priority: 여러 스레드가 기다릴 때, 누가 먼저 실행될지 정하는 기준

ready_list에 들어간 스레드는 모두 THREAD_READY 상태이고,
CPU를 받을 기회를 기다리고 있는 중이다.

실행 순서의 기준: priority

운영체제는 스레드들을 단순히 먼저 온 순서로 실행하지 않는다.
대신, 우선순위(priority)를 기준으로 스레드를 줄을 세운다.

"더 급한 스레드 먼저 실행시켜줘!"
이런 방식이다.

PintOS Project 1에서 우리가 한 일은?

우리는 이 스레드 관리 기능 전체를 직접 구현했다.


1. 스레드 만들기 – thread_create()

tid_t thread_create(const char *name, int priority, thread_func *function, void *aux);

새로운 스레드를 만든다.

이 스레드는 당장 실행되는 게 아니라,
CPU 대기열인 ready_list에 들어간다.

스레드 하나 만들고, 대기 줄에 세운다!

2. 실행 대기 – ready_listschedule()

ready_list는 말 그대로 “누가 다음으로 CPU 쓸까?” 하는 줄이다.
여기엔 스레드들이 우선순위 순으로 정렬되어 있다.

schedule() 함수는 ready_list를 보고

가장 우선순위 높은 스레드를 골라서 실행시킨다.

줄에서 1등 스레드를 골라 CPU를 준다!

3. CPU 양보 – thread_yield()

스레드가 자발적으로 CPU를 양보하고 싶을 때가 있다.
예를 들어,
“지금보다 더 급한 스레드가 생겼네? 난 좀 쉬자~” 이런 느낌이다.

thread_yield();

스레드는 다시 ready_list에 들어가고
schedule()이 다른 스레드를 실행시킨다.

내가 먼저였지만, CPU 잠깐 줄게!

4. 멈추기 – thread_block()

스레드가 무조건 CPU를 계속 갖고 있을 순 없다.
자원을 기다려야 할 수도 있고,
시간이 되기 전까진 실행되면 안 될 수도 있다.

thread_block();

실행 중이던 스레드를 멈추고 blocked 상태로 만든다.
ready_list에서도 제외된다.

난 지금 못 움직여 .. 자원이 올 때까지 멈출게!

5. 다시 깨우기 – thread_unblock()

thread_unblock(thread *t);

기다리던 자원이 생기거나,

타이머가 끝나면
스레드를 다시 ready_list에 넣어준다.

자원 생겼어! 이제 나도 줄 설게 ~


🐭 짤막한 회고

처음엔 스레드(thread)가 정말 추상적으로 다가왔는데,
CPU가 명령어를 실행해가는 하나의 흐름이라는 것의 의미를
이번 프로젝트를 통해 비로소 제대로 이해하게 된 것 같다.

중간에 알 수 없는 오류들로 여러번 당황했지만,
팀원이 gdb 사용법을 알려줘서 디버깅하는 방법도 익혀갈 수 있었다.
오류를 마주해도 당황하지 않고 하나씩 들여다보는 힘이 생긴 것 같아 뿌듯하다.

profile
이유민

0개의 댓글