오늘 하루종일 priotity-donate-one으로 삽질하다 팀원이 도와줘서 (사실상 옆에서 떠먹여줘서) 해결함. -> 이거 해결하니 priority-sema도 해결이 되더라.
문제상황은 이렇다.
- 우선순위가 높은 쓰레드 H, 중간 M 그리고 낮은 L가 있다고 생각해보세요.
- 만약 L이 락을 갖고있어서 H가 L을 기다려야하고 M이 ready list에 있다면, H는 절대로 CPU를 사용하지 못할 것입니다.
- 왜냐면 낮은 우선순위의 스레드가 CPU시간을 얻지 못할 것이기 때문입니다.
- 이 문제에 대한 부분적으로 해결하는 방법은 L이 락을 갖는 동안 H가 L에게 우선순위를 기부(donate)한 다음, L이 잠금을 해제하면 (따라서 H가 획득) 이 기부를 회수하는 것입니다.
donate-one 을 해결하려면 고쳐야 할 부분이 몇 군데 있다.//threads.h
int original_priority; /* 기존 우선순위 */
struct lock *l; /* 스레드가 기다리고 있는 락 */
original_priority 도 업테이트 해줘야 함.
void thread_set_priority(int new_priority)
{
struct thread *curr = thread_current(); // 현재 스레드 가져오기
curr->priority = new_priority; // 우선순위를 직접 변경
curr->original_priority = new_priority;
// 추가
if (thread_current()->priority < list_entry(list_begin(&ready_list), struct thread, elem)->priority)
{
thread_yield();
}
}
사실 이 부분은 앞서 문제를 다 푼 다른 동기가 고쳐야 할것 이라고 강력하게 주장했지만, 일단 당장 풀고있는 테스트 케이스는 통과됐고, 추후 변경이 필요하면 그 때 변경해보려 함.
// synch.c
void sema_down(struct semaphore *sema)
{
enum intr_level old_level;
ASSERT(sema != NULL);
ASSERT(!intr_context());
old_level = intr_disable();
struct lock *lock = thread_current()->l;
while (sema->value == 0)
{
// list_push_back(&sema->waiters, &thread_current()->elem);
list_insert_ordered(&sema->waiters, &thread_current()->elem, compare_thread, NULL);
// 대기자의 우선순위가 락의 홀더보다 높으면 기부
if (lock && thread_current()->priority > lock->holder->priority)
{
lock->holder->priority = thread_current()->priority;
}
thread_block();
}
sema->value--;
intr_set_level(old_level);
}
// synch.c
void sema_up(struct semaphore *sema)
{
enum intr_level old_level;
ASSERT(sema != NULL);
struct lock *lock = thread_current()->l;
old_level = intr_disable();
if (!list_empty(&sema->waiters))
thread_unblock(list_entry(list_pop_front(&sema->waiters),
struct thread, elem));
sema->value++;
thread_current()->priority = thread_current()->original_priority;
if (thread_current()->priority < list_entry(list_begin(&ready_list), struct thread, elem)->priority)
{
thread_yield();
}
intr_set_level(old_level);
}