몇 초만에 프로세스를 깨우는 시스템 호출
스레드를 sleep and wakeup 으로 이루어진 알람 시계를 만든다.
상태 주기

원래 상태

바꿔야 하는 상태

sleep 큐 데이터 구조를 초기화하는 코드 추가.
구현 전 힌트는 없다.
// threads/thread.h
int64_t wakeup_ticks; // 일어날 시각 추가(각 스레드 마다 존재)
void thread_sleep (int64_t ticks);
void thread_wakeup (int64_t global_ticks);
bool cmp_thread_ticks(const struct list_elem *a, const struct list_elem *b, void *aux);
threads/thread.c
static struct list ready_list;
static struct list sleep_list;
thread_init(void)
{
list_init(&sleep_list);
}
sleep 큐에 스레드를 삽입하는 함수 호출
구현 전 힌트는 없다.
devices/timer.c
timer_sleep(int64_t ticks)
{
int64_t start = timer-ticks(); // 현재 시각
ASSERT(intr_get_level() == INTR_ON); // 인터럽트 레벨 검사
thread_sleep(start + ticks); // 현재 시각 + 잠들시간
}
매 틱 마다 일부 스레드가 절전 대기열에서 깨어나야하는지 확인하고 wake up 함수 호출
구현 전 힌트
sleep list와 global tick 확인. 깨울 스레드를 찾으세요. 필요한 경우 ready_list로 이동하세요.
devices/timer.c
timer_interrupt(struct intr_frame *args UNSED)
{
ticks++;
thread_tick (); // 스레드의 우선순위를 관리, 다음 실행할 스레드를 선택하는 역할.
thread_wakeup(ticks); // 일어날 시간이 된 스레드 > ready_list로 이동시키는 함수 호출
}
스레드 상태를 차단됨으로 설정하고 절전 대기열에 삽입한 후 대기하는 함수. 스레드를 블록처리 함으로써 재우는 함수.
구현 전 힌트
threads/thread.c
thread_sleep(int64_t ticks)
{
struct thread *curr;
enum intr_level old_level;
// 1. 인터럽트 비활성화
old_level = intr_disable();
// 2. 현재 스레드 가져오기
curr = thread_current();
// 3. 스레드 검사(현재 스레드가 idle이 아닐때만)
ASSERT(curr != idle_thread);
// 4. 일어날 시각 설정
curr->wakeup_ticks = ticks;
// 5. sleep_list에 스레드 추가
list_insert_ordered(&sleep_list, &curr->elem, cmp_thread_ticks, NULL); // sleep_list에 추가
// 6. 스레드 블록(재우기) - 블록 처리
thread_block(); //
// 7. 인터럽트 복원
intr_set_level(old_level);
}
절전 대기열에서 깨어날 스레드를 찾아 절전 모드를 해제하는 함수. 잠든 상태인 스레드를 깨우는 함수
구현 전 힌트(x)
threads/thread.c
thread_wakeup(int64_t current_ticks)
{
enum intr_level old_level;
// 1. 인터럽트 비활성화
old_level = intr_disable();
struct list_elem *curr_elem = list_begin(&sleep_list);
// 2. 'sleep_list' 순회
while (curr_elem != list_end(&sleep_list))
{
struct thread *curr_thread = list_entry(curr_elem, struct thread, elem); // 현재 검사중인 elem의 스레드
// 3. 스레드 깨우기
if (current_ticks >= curr_thread->wakeup_ticks)
{
// 3-1. 순회 계속(sleep_list에서 제거, curr_elem에는 다음 elem이 담김)
curr_elem = list_remove(curr_elem);
// 3-2. 스레드 깨우기(ready_list로 이동)
thread_unblock(curr_thread);
}
else
break;
}
// 5. 인터럽트 **복원(**활성화**)**
intr_set_level(old_level); // 인터럽트 상태를 원래 상태로 변경(활성화)
}
목표는 일정 시간이 지나면 프로세스를 깨우는 알람 시스템 구현.
thread_init()은 sleep_list 초기화
timer_sleep(ticks)은 현재 시간 + 대기 시간 계산 해서 thread_sleep()호출
thread_selle(ticks)은 현재 스레드를 sleep_list에 넣고서 block 처리함.
timer_interrupt()은 매 틱마다 thread_wakeup() 호출함.
thread_wakeup(ticks)은 깨어날 시간이 지난 스레드를 깨워서 ready_list에 넣음
각 스레드에 wakeup tick을 기록해두고, 매 틱마다 그 시간을 비교해서 다시 실행 대기 상태로 전환하는 구조. 정렬된 sleep_list를 통해서 깨어날 스레드만 효율적으로 순회할 수 있도록 구현.
스레드가 cpu를 점유하지 않고 기다리고, BLOCKED → READY → RUNNING 상태 전이로 효율적인 스케줄링이 된다.
멀티스레드 환경에서는 중요한 자료구조를 수정할 때 꼭 인터럽트를 끄고 작업함. 인터럽트가 발생해서 다른 코드가 동시에 같은 리스트를 건드릴 수 있다. 운영체제 커널이 이런 방식으로 동기화 사용함.