[Pintos-KAIST] Project 1 :: Priority Scheduling
2023. 4. 25. 23:46ใComputer Science
728x90
๋ฐ์ํ
Priority Scheduling
๐ก ์ฐ์ ์์๊ฐ ๋์ ์ค๋ ๋๊ฐ ๋จผ์ CPU๋ฅผ ์ ์ ํ ์ ์๋๋ก Priority Scheduling์ ๊ตฌํํ๋ค.
Priority Scheduling ๊ตฌํ์ฌํญ
- ์ค๋ ๋๋ค์ ๊ฐ ์ฐ์ ์์์ ๋ฐ๋ผ ready list์ ์ถ๊ฐ๋๋ค.
- ํ์ฌ ์คํ ์ค์ธ ์ค๋ ๋์ ์ฐ์ ์์๋ณด๋ค ๋์ ์ฐ์ ์์์ ์ค๋ ๋๊ฐ ready list์ ์ถ๊ฐ๋๋ฉด, ํ์ฌ ์คํ ์ค์ธ ์ค๋ ๋๋ ๋ฐ๋ก CPU๋ฅผ ์๋ํ๋ค.
- ์ค๋ ๋๋ ์ธ์ ๋ ์ง ์์ ์ ์ฐ์ ์์๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
- ์ฐ์ ์์๋ฅผ ๋ฎ์ถ์ด ๋์ด์ ๊ฐ์ฅ ๋์ ์ฐ์ ์์๊ฐ ์๋๊ฒ ๋๋ค๋ฉด, ์ฆ์ CPU๋ฅผ ์๋ํ๋ค.
- lock, semaphore, condition variable์ ์ฌ์ฉํ์ฌ ๋๊ธฐํ๊ณ ์๋ ์ค๋ ๋๊ฐ ์ฌ๋ฌ ๊ฐ์ธ ๊ฒฝ์ฐ, ์ฐ์ ์์๊ฐ ๊ฐ์ฅ ๋์ ์ค๋ ๋๊ฐ ๋จผ์ ๊นจ์ด๋์ผ ํ๋ค.
๊ตฌํํ๊ธฐ
(1) ready_list ์ ๋ ฌ
thread_yield
, thread_unblock
- ready_list์ ์ค๋ ๋๋ฅผ ์ฝ์
ํ ๋ priority๊ฐ ๋์ ์ค๋ ๋๊ฐ ์๋ถ๋ถ์ ์์นํ๋๋ก ์ ๋ ฌํ๋ค.
- ๊ธฐ์กด์๋ list_push_back์ ์ฌ์ฉํด FIFO ๋ฐฉ์์ผ๋ก ์ฝ์ ๋๊ณ ์์๋ค.
- list_insert_ordered๋ฅผ ํ์ฉํ๋ค.
- ์ ๋ ฌ์ ํ์ฉํ cmp_thread_priority() ํจ์๋ ์๋์์ ์๋ก ์ ์ธํ๋ค.
/* thread.c */
void thread_yield(void)
{
struct thread *curr = thread_current();
enum intr_level old_level;
ASSERT(!intr_context());
old_level = intr_disable();
if (curr != idle_thread)
list_insert_ordered(&ready_list, &curr->elem, cmp_thread_priority, NULL);
do_schedule(THREAD_READY);
intr_set_level(old_level);
}
/* thread.c */
void thread_unblock(struct thread *t)
{
enum intr_level old_level;
ASSERT(is_thread(t));
old_level = intr_disable();
ASSERT(t->status == THREAD_BLOCKED);
list_insert_ordered(&ready_list, &t->elem, cmp_thread_priority, NULL);
t->status = THREAD_READY;
intr_set_level(old_level);
}
cmp_thread_priority
- ready_list์ priority๊ฐ ๋์ ์ค๋ ๋๊ฐ ์๋ถ๋ถ์ ์์นํ๋๋ก ์ ๋ ฌํ ๋ ์ฌ์ฉํ ์ ๋ ฌ ํจ์๋ฅผ ์๋ก ์ ์ธํ๋ค.
/* thread.h */
bool cmp_thread_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED);
/* thread.c */
bool cmp_thread_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED)
{
struct thread *st_a = list_entry(a, struct thread, elem);
struct thread *st_b = list_entry(b, struct thread, elem);
return st_a->priority > st_b->priority;
}
(2) Preempt
thread_create
, thread_wakeup
- ready_list์ ์ค๋ ๋๊ฐ ์ฝ์ ๋๊ณ ๋๋ฉด, ํ์ฌ ์คํ์ค์ธ ์ค๋ ๋์ ready_list์ ์๋ ์ค๋ ๋์ priority๋ฅผ ๋น๊ตํ๋ค.
- priority๊ฐ ๋ ๋์ ์ค๋ ๋๊ฐ ready_list์ ์๋ค๋ฉด ์ฆ์ CPU๋ฅผ ์๋ณดํ๋ค. (
preempt_priority()
ํธ์ถ )- ์๋ณด ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ ์๋ณดํ๋ preempt_priority() ํจ์๋ ์๋์์ ์๋ก ์ ์ธํ๋ค.
/* thread.c */
tid_t thread_create(const char *name, int priority,
thread_func *function, void *aux)
{
...
/* Add to run queue. */
thread_unblock(t);
preempt_priority();
return tid;
}
/* thread.c */
void thread_wakeup(int64_t current_ticks)
{
enum intr_level old_level;
old_level = intr_disable(); // ์ธํฐ๋ฝํธ ๋นํ์ฑ
struct list_elem *curr_elem = list_begin(&sleep_list);
while (curr_elem != list_end(&sleep_list))
{
struct thread *curr_thread = list_entry(curr_elem, struct thread, elem); // ํ์ฌ ๊ฒ์ฌ์ค์ธ elem์ ์ค๋ ๋
if (current_ticks >= curr_thread->wakeup_ticks) // ๊นฐ ์๊ฐ์ด ๋์ผ๋ฉด
{
curr_elem = list_remove(curr_elem); // sleep_list์์ ์ ๊ฑฐ, curr_elem์๋ ๋ค์ elem์ด ๋ด๊น
thread_unblock(curr_thread); // ready_list๋ก ์ด๋
preempt_priority();
}
else
break;
}
intr_set_level(old_level); // ์ธํฐ๋ฝํธ ์ํ๋ฅผ ์๋ ์ํ๋ก ๋ณ๊ฒฝ
}
thread_set_priority
- ์คํ์ค์ธ thread์ priority๋ฅผ ๋ณ๊ฒฝ๋๋ฏ๋ก ready_list์ ์๋ ์ค๋ ๋๋ณด๋ค priority์ ๋น๊ตํ์ฌ ํ์ฌ ๋ณ๊ฒฝ๋ priority๊ฐ ๋ ๋ฎ๋ค๋ฉด, ์ฆ์ CPU๋ฅผ ์๋ณดํ๋ค. (
preempt_priority()
ํธ์ถ )
/* thread.c */
void thread_set_priority(int new_priority)
{
thread_current()->init_priority = new_priority;
preempt_priority();
}
preempt_priority
- ready_list์ ์๋ ์ค๋ ๋์ priority๊ฐ ํ์ฌ ์คํ์ค์ธ ์ค๋ ๋์ priority๋ณด๋ค ๋์ผ๋ฉด ์๋ณดํ๋ ํจ์๋ฅผ ์๋ก ์ ์ธํ๋ค.
- ready_list๋ priority๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ๋๋ฏ๋ก, ๊ฐ์ฅ ์์ ์๋ ์ค๋ ๋๋ง ๊ฒ์ฌํ๋ฉด ๋๋ค.
/* thread.h */
void preempt_priority(void);
/* thread.c */
void preempt_priority(void)
{
if (thread_current() == idle_thread)
return;
if (list_empty(&ready_list))
return;
struct thread *curr = thread_current();
struct thread *ready = list_entry(list_front(&ready_list), struct thread, elem);
if (curr->priority < ready->priority) // ready_list์ ํ์ฌ ์คํ์ค์ธ ์ค๋ ๋๋ณด๋ค ์ฐ์ ์์๊ฐ ๋์ ์ค๋ ๋๊ฐ ์์ผ๋ฉด
thread_yield();
}
Test - Priority 1
/* Test: /threads์์ ์
๋ ฅ */
make check
๐๐ป ๊ตฌํ ์
๐๐ป ๊ตฌํ ํ
priority ๊ด๋ จ ํ ์คํธ 4๊ฐ๋ฅผ ๋ ํต๊ณผํ๋ค!
(3) Lock Waiters ์ ๋ ฌ
- lock, semaphore, condition variable์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ๋๊ธฐํ๊ณ ์๋ ์ค๋ ๋๊ฐ ์ฌ๋ฌ ๊ฐ์ธ ๊ฒฝ์ฐ, lock์ ํ๋ํ ์ ์์ด์ก์ ๋ priority๊ฐ ๊ฐ์ฅ ๋์ ์ค๋ ๋๊ฐ ๋จผ์ ๊นจ์ด๋์ผ ํ๋ค.
- lock์ ๋๊ธฐ์ ๋ชฉ๋ก์ธ waiters๋ priority ๊ธฐ์ค์ผ๋ก ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ๋ก ๋ณ๊ฒฝํ๋ค.
- ๐ก semaphore
- ์ธ๋งํฌ์ด๋ ์์ ์ ์๊ฐ๊ณผ ๋ ๊ฐ์ ์ฐ์ฐ์(P์ V)๋ก ๊ตฌ์ฑ๋ ๋๊ธฐํ ๊ธฐ๋ฒ์ด๋ค.
- "Down" ๋๋ "P"
- ์ธ๋งํฌ์ด๋ฅผ ํ๋ํ๊ธฐ ์ํด(๊ณต์ ์์์ ์ ๊ทผํ๋ ค ํ ๋) ํธ์ถํ๋ค.
- ํ๋ํ๋ฉด ์ธ๋งํฌ์ด๋ฅผ ํ๋ํ๋ค๋ ์๋ฏธ๋ก value๋ฅผ 1 ๊ฐ์์ํจ๋ค.
- ์ธ๋งํฌ์ด๋ฅผ ํ๋ํ ๋๊น์ง(value๊ฐ ์์๊ฐ ๋ ๋๊น์ง) ๊ธฐ๋ค๋ฆฐ๋ค.(๋ธ๋ก๋๋ค.)
- ์ธ๋งํฌ์ด๋ฅผ ๋ฐ๋ก ํ๋ํ ์ ์์ ๋๋ ์ค๋ ๋๊ฐ ๊ธฐ๋ค๋ฆฌ๊ฒ ๋๋๋ฐ(๋ธ๋ก๋จ),
๊ธฐ๋ค๋ฆฌ๋ ๋์(๋ธ๋ก๋์ด ์๋ ๋์)์๋ ๋ค๋ฅธ ์ค๋ ๋๊ฐ ์ธ๋งํฌ์ด๋ฅผ ๋จผ์ ํด์ (UP)ํ๊ณ ๋์, ์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์ค๋ ๋๊ฐ ์คํ๋๊ฒ ๋๋ค.
- "UP" ๋๋ "V"
- ์ธ๋งํฌ์ด๋ฅผ ๋ฐํํ ๋(๊ณต์ ์์ ์ฌ์ฉ์ ์๋ฃํ์ ๋) ํธ์ถํ๋ค.
- ๋๊ธฐ ์ค์ธ ์ค๋ ๋ ์ค ํ๋๋ฅผ ๊นจ์์ฃผ๊ณ , ์ธ๋งํฌ์ด์ value๋ฅผ ๋ฐํํ๋ค๋ ์๋ฏธ๋ก 1 ์ฆ๊ฐ์ํจ๋ค.
sema_down
, cond_wait
- waiters์ ์ค๋ ๋๋ฅผ ์ฝ์
ํ ๋ priority๊ฐ ๋์ ์ค๋ ๋๊ฐ ์๋ถ๋ถ์ ์์นํ๋๋ก ์ ๋ ฌํ๋ค.
- list_insert_ordered๋ฅผ ํ์ฉํ๋ค.
- sema→waiters๋ฅผ ์ ๋ ฌํ ๋ ์ฌ์ฉํ๋ cmp_thread_priority ํจ์๋ ready_list๋ฅผ ์ ๋ ฌํ ๋ ์ฌ์ฉํ ํจ์๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค.
- cond→waiters๋ฅผ ์ ๋ ฌํ ๋ ์ฌ์ฉํ๋ cmp_sema_priority ํจ์๋ ์๋์์ ์๋ก ์ ์ธํ๋ค.
/* synch.c */
void sema_down(struct semaphore *sema)
{
enum intr_level old_level;
ASSERT(sema != NULL);
ASSERT(!intr_context());
old_level = intr_disable();
while (sema->value == 0) // ์ธ๋งํฌ์ด ๊ฐ์ด 0์ธ ๊ฒฝ์ฐ, ์ธ๋งํฌ์ด ๊ฐ์ด ์์๊ฐ ๋ ๋๊น์ง ๋๊ธฐ
{
list_insert_ordered(&sema->waiters, &thread_current()->elem, cmp_thread_priority, NULL);
thread_block(); // ์ค๋ ๋๋ ๋๊ธฐ ์ํ์ ๋ค์ด๊ฐ
}
sema->value--; // ์ธ๋งํฌ์ด ๊ฐ์ด ์์๊ฐ ๋๋ฉด, ์ธ๋งํฌ์ด ๊ฐ์ 1 ๊ฐ์
intr_set_level(old_level);
}
/* synch.c */
void cond_wait(struct condition *cond, struct lock *lock)
{
struct semaphore_elem waiter;
ASSERT(cond != NULL);
ASSERT(lock != NULL);
ASSERT(!intr_context());
ASSERT(lock_held_by_current_thread(lock));
sema_init(&waiter.semaphore, 0);
list_insert_ordered(&cond->waiters, &waiter.elem, cmp_sema_priority, NULL);
lock_release(lock);
sema_down(&waiter.semaphore);
lock_acquire(lock);
}
cmp_sema_priority
- cond→waiters๋ฅผ ์ ๋ ฌํ ๋ ์ฌ์ฉํ ํจ์๋ฅผ ์๋ก ์ ์ธํ๋ค.
- ์ธ์๋ก ์ ๋ฌ๋๋ elem์ผ๋ก ๋ฐ๋ก ์ค๋ ๋์ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์, ์ด์ ์ cmp_thread_priority๋ฅผ ์ธ ์ ์์ด์ ์๋ก ์ ์ธํด์ผ ํ๋ค!
- ๋ semahore ์์ 'waiters ์ค ์ ์ผ ๋์ priority'๋ฅผ ๋น๊ตํด์ ๋์ผ๋ฉด true๋ฅผ ๋ฐํํ๋ ํจ์
/* thread.h */
bool cmp_sema_priority(const struct list_elem *a, const struct list_elem *b, void *aux);
/* synch.c */
bool cmp_sema_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED)
{
struct semaphore_elem *sema_a = list_entry(a, struct semaphore_elem, elem);
struct semaphore_elem *sema_b = list_entry(b, struct semaphore_elem, elem);
struct list *waiters_a = &(sema_a->semaphore.waiters);
struct list *waiters_b = &(sema_b->semaphore.waiters);
struct thread *root_a = list_entry(list_begin(waiters_a), struct thread, elem);
struct thread *root_b = list_entry(list_begin(waiters_b), struct thread, elem);
return root_a->priority > root_b->priority;
}
sema_up
, cond_signal
- waiters์์ ์ค๋ ๋๋ฅผ ๊นจ์ฐ๊ธฐ ์ ์ waiters ๋ชฉ๋ก์ ๋ค์ ํ ๋ฒ ์ ๋ ฌํ๋ค.
- waiters์ ๋ค์ด์๋ ์ค๋ ๋๊ฐ donate๋ฅผ ๋ฐ์ ์ฐ์ ์์๊ฐ ๋ฌ๋ผ์ก์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
- sema_up์์๋ unblock() ํจ์๊ฐ ํธ์ถ๋๋ฉด์ ready_list์ ์ค๋ ๋๊ฐ ์ฝ์
๋๋ฏ๋ก, priority๊ฐ ๋ ๋์ ์ค๋ ๋๊ฐ ready_list์ ์๋ค๋ฉด ์ฆ์ CPU๋ฅผ ์๋ณดํ๋ค. (
preempt_priority()
ํธ์ถ )
/* synch.c */
void sema_up(struct semaphore *sema)
{
enum intr_level old_level;
ASSERT(sema != NULL);
old_level = intr_disable();
if (!list_empty(&sema->waiters)) // ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ฅผ ๊นจ์
{
// waiters์ ๋ค์ด์๋ ์ค๋ ๋๊ฐ donate๋ฅผ ๋ฐ์ ์ฐ์ ์์๊ฐ ๋ฌ๋ผ์ก์ ์ ์๊ธฐ ๋๋ฌธ์ ์ฌ์ ๋ ฌ
list_sort(&sema->waiters, cmp_thread_priority, NULL);
thread_unblock(list_entry(list_pop_front(&sema->waiters), struct thread, elem));
}
sema->value++;
preempt_priority(); // unblock์ด ํธ์ถ๋๋ฉฐ ready_list๊ฐ ์์ ๋์์ผ๋ฏ๋ก ์ ์ ์ฌ๋ถ ํ์ธ
intr_set_level(old_level);
}
/* synch.c */
void cond_signal(struct condition *cond, struct lock *lock UNUSED)
{
ASSERT(cond != NULL);
ASSERT(lock != NULL);
ASSERT(!intr_context());
ASSERT(lock_held_by_current_thread(lock));
if (!list_empty(&cond->waiters))
{
list_sort(&cond->waiters, cmp_sema_priority, NULL);
sema_up(&list_entry(list_pop_front(&cond->waiters),
struct semaphore_elem, elem)
->semaphore);
}
}
Test - Priority 2
/* Test: /threads์์ ์
๋ ฅ */
make check
๐๐ป ๊ตฌํ ์
๐๐ป ๊ตฌํ ํ
priority - sema, condvar ํ ์คํธ 2๊ฐ๋ฅผ ๋ ํต๊ณผํ๋ค!
728x90
๋ฐ์ํ
'Computer Science' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Pintos-KAIST] Project 1 :: Priority Donation (0) | 2023.04.26 |
---|---|
[Pintos-KAIST] Project 1 :: Alarm Clock (Sleep-Awake ๋ฐฉ์์ Alarm Clock ๊ตฌํํ๊ธฐ) (0) | 2023.04.25 |
Why Is Code Review Necessary? (0) | 2023.04.04 |