
cond_signal()은 조건 변수의 대기 큐 중 제일 priority가 높은 쓰레드를 깨워야 함.cond_wait()에서 struct condition의 대기 큐 waiters에 쓰레드를 priority의 내림차순으로 삽입해야 함.ready_list의 삽입에 사용했던 우선순위 비교 함수를 그대로 사용 시, 테스트 케이스를 통과하지 못함.// 잘못된 방식
void cond_wait(struct condition *cond, struct lock *lock){
// 생략...
// cond의 대기 큐에 현재 쓰레드를 priority 역순으로 삽입
list_insert_ordered (&cond->waiters, &waiter.elem, dsc_priority, NULL);
}
/* priority의 내림차순 정렬에 사용되는 함수. */
bool dsc_priority (const struct list_elem *x, const struct list_elem *y, const void *aux){
struct thread *tx = list_entry(x, struct thread, elem);
struct thread *ty = list_entry(y, struct thread, elem);
return (tx -> priority) > (ty -> priority);
}
struct semaphore_elem {
struct list_elem elem;
struct semaphore semaphore;
};
waiters에는 struct thread의 elem이 아니라, struct semaphore_elem의 elem이 들어감elem이 struct thread의 일부라고 가정하고, priority 멤버를 참고하려고 함list_entry는 elem이 struct thread의 일부라고 가정하고, 이를 바탕으로 priority의 주소를 계산struct semaphore_elem에는 priority가 없으므로, 잘못된 주소 참조로 정렬 실패struct semaphore_elem {
struct list_elem elem; /* List element. */
struct semaphore semaphore; /* This semaphore. */
struct thread *thread; // 해당 쓰레드를 가리킴
};
void cond_wait(struct condition *cond, struct lock *lock){
// 생략...
struct semaphore_elem waiter;
waiter.thread = thread_current();
}
semaphore_elem에 원래 thread의 주소를 가리키는 thread 멤버를 추가/* waiters 리스트 -> priority의 내림차순으로 정렬할 시 사용되는 함수. */
bool dsc_sema_priority (const struct list_elem *x, const struct list_elem *y, const void *aux){
struct semaphore_elem *tx = list_entry(x, struct semaphore_elem, elem);
struct semaphore_elem *ty = list_entry(y, struct semaphore_elem, elem);
return (tx -> thread -> priority) > (ty -> thread -> priority);
}
list_insert_ordered (&cond->waiters, &waiter.elem, dsc_sema_priority, NULL);
dsc_sema_priority 함수를 만들어, semaphore_elem 기준으로 주소를 찾음thread 멤버로 원래 struct thread에 접근하고 priority를 비교struct thread: 쓰레드 관리 구조체struct thread 구조체로 관리됨enum thread_status status 멤버는 쓰레드의 현재 상태를 나타냄THREAD_RUNNING: cpu에서 실행 중.THREAD_READY: ready queue에서 실행할 준비가 된 상태. 현재 실행 중이진 않지만 BLOCKED 상태도 아닌 쓰레드.THREAD_BLOCKED: 특정 이벤트를 기다리는 쓰레드. sleep timer 종료라든가, 세마포어/뮤텍스 해제라든가.THREAD_DYING: 삭제 예정인 쓰레드. 실행 중인 쓰레드를 바로 삭제할 순 없으므로, 일단 이 상태로 표시해 두었다가 이후 스케줄러가 해당 쓰레드를 정리.
thread_create(): 쓰레드 생성tid_t thread_create (const char *name, int priority,
thread_func *function, void *aux)
name의 쓰레드를 생성하고, 우선순위 priority 설정function 실행 (매개변수 aux 전달)TID_ERROR 반환)ready_list, all_list: 쓰레드 리스트// 흔히 ready queue라 불림
// THREAD_READY 상태의 쓰레드를 관리
static struct list ready_list;
// 모든 쓰레드 (running + ready + blocked)를 관리
// 처음으로 스케줄링될 때 삽입되고, 쓰레드가 종료될 때 삭제됨
static struct list all_list;
all_list 맨 끝에 삽입됨ready_list에 삽입됨ready_list는 우선순위의 역순으로 정렬됨 -> 올바른 위치를 찾아 삽입됨schedule, do_schedule: 쓰레드 스케줄링static void schedule (void){
// 현재 실행 중인 쓰레드
struct thread *curr = running_thread ();
// ready_list 맨 앞 쓰레드. 비어 있으면 idle 쓰레드
struct thread *next = next_thread_to_run ();
// 다음 쓰레드를 실행 처리
next->status = THREAD_RUNNING;
if (curr != next){
// 문맥 전환을 실제로 수행하는, 어셈블리어로 가득한 함수
thread_launch (next);
}
}
ready_list의 맨 앞 쓰레드로 문맥 전환 수행status를 THREAD_RUNNING으로 전환ready_list 맨 앞 쓰레드가 동일하지 않은 경우, thread_launch로 문맥 전환 (어셈블리어로 가득해 일단 생략)// status로 쓰레드 상태 변경
void do_schedule(int status){
// 현재 쓰레드의 status를 매개변수로 바꾼다.
thread_current ()->status = status;
// 새롭게 스케줄링
schedule ();
}

do_schedule()에서 쓰레드 상태 변경을 해 주고, do_schedule() 내부에서 schedule()을 호출do_schedule이 호출되기 전엔 인터럽트가 해제되어야 함thread_exit())THREAD_DYING으로 변경thread_block())THREAD_BLOCKED로 변경yield 시스템 콜을 보낼 때 (thread_yield())THREAD_READY로 변경THREAD_READY로 변경ready_list 맨앞 노드가 현재 쓰레드의 priority보다 높은 경우, thread_yield()를 실행하는 식으로 구현status 변경해 준다고 ready_list에서 자동으로 쓰레드가 삽입 / 삭제되지는 않음에 유의프로세스: 실행 중인 프로그램
프로세스 생성 시 커널 영역에 PCB(프로세스 컨트롤 블록)이 생성됨
문맥 교환: 프로세스 간 실행을 전환하는 것


뮤텍스 락의 구현
lockfalse면 열려 있고, true면 잠겨 있음acquire 함수lock이 false: lock을 true로 바꾸고, 임계 구역에서의 작업을 진행lock이 true: lock이 false가 될 때까지 임계 구역 밖에서 대기 (대기 큐에 삽입)release 함수lock을 false로 바꾸고, 대기 큐의 프로세스 중 1개(보통 우선순위가 제일 높은 친구)를 준비 큐로 옮김release는 현재 뮤텍스 락을 acquire한 작업 단위만 수행할 수 있음acquire(), release() 함수를 두어 보호할 수 있음acquire();
// 임계 구역
release();
세마포어의 구현
semaphoresemaphore == 0일 때 잠김 (더 작업단위가 못 들어온단 소리)wait 함수semaphore >= 1이라면, semaphore를 1 감소시키고 임계 구역에 진입semaphore == 0이라면, semaphore가 1 이상의 값이 될 때까지 임계 구역 밖에서 대기 (대기 큐에 삽입)signal 함수semaphore를 1 증가시키고, 대기 큐의 프로세스 중 1개(보통 우선순위가 제일 높은 친구)를 준비 큐로 옮김wait();
// 임계 구역
signal();
wait 연산: 호출한 작업 단위를 대기 상태로 전환 후, 조건 변수의 대기 큐에 삽입signal 연산: wait를 이용해 조건 변수의 대기 큐에 삽입된 프로세스의 실행을 재개
