https://poalim.tistory.com/35?category=758538
๐๊ฑฐ์ ๋๋ถ๋ถ์ ๋์์ ํด๋น ๋งํฌ์์ ๋ฐ์์์ต๋๋ค.
https://web.eecs.umich.edu/~akamil/teaching/sp04/pri/#fig:inversion
Priority Scheduling ์ ํ๋ก์ธ์ค ํน์ ์ฐ๋ ๋ ์ค ๋ค์์ ๋ฌด์์ด ์คํ ๋ ์ง scheduling ํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
์ด๋ฅผ priority๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ์ ํ๊ฒ ๋๋ฉด priority scheduling์ด๋ค. Priority๋ thread ๊ตฌ์กฐ์ฒด์ ๋งด๋ฒ๋ก ๊ฐ ์ฐ๋ ๋์ ๊ธฐ๋ก๋๋ค. thread_ready state ์ธ thread๋ค์ด ready_list์ priority ๊ธฐ์ค ์ค๋ฆ ์ฐจ์์ผ๋ก ๊ธฐ๋ก๋์ด์๋ค.
https://web.eecs.umich.edu/~akamil/teaching/sp04/pri/#fig:inversion
priority๊ฐ ๋ฎ์ thread(A or L)์ด Key๋ฅผ ๋ค๊ณ ์์ ๋, ์คํ ์ค์ธ thread(H, C)๊ฐ key๋ฅผ ์์ฒญํ๋ ๊ฒฝ์ฐ, key๊ฐ ๋ค๋ฅธ thread์๊ฒ ์ข ์๋์ด์๊ธฐ์ key๊ฐ ๋ฐํ ๋ ๋๊น์ง thread(H, C)๋ Blocked state๋ก ๋ค์ด๊ฐ๊ณ , ๊ทธ ํ schedule์ ์ํด ๋ค์ priority ์ธ thread(B, M)์ด ์คํ๋๋๋ฐ, ์ด ์ํฉ์ด Priority inversion์ด๋ค. Priority๊ฐ ๋์ thread(H, L)์ด ๋ฉ์ฉกํ ์๋๋ฐ priority๊ฐ ์๋์ ์ผ๋ก ๋ฎ์ thread(B, M)์ด ์คํ๋๋ Inversion ์ด๋ค.
thread ๋ค์ ํ ํ๋ก์ธ์ค ์์์ ์์ฑ๋๋ ์ฌ๋ฌ๊ฐ์ ์คํ ํ๋ฆ์ธ๋ฐ ์ด๋ค์ ํ๋ก์ธ์ค์ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ณต์ ํ๋ค. ์ด๋ ์๋ก ๋์์ ํ ์์์ ๊ฑด๋๋ฆด ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ์๊ธด๋ค. ์ด๋ฅผ ์ ์ดํ๊ธฐ ์ํด semaphore/lock/conditional variable๋ฑ์ ์ด์ฉํ๋ค.
https://renelemon.tistory.com/99?category=950734
์์ ๊ฐ์ Inversion case๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด priority donation ๊ธฐ๋ฅ์ ๋ง๋ค์.
Priority Donation์ key holder thread์๊ฒ lock์ ์์ฒญํ๊ณ ์๋ thread์ priority๋ฅผ donateํด์ฃผ์ด donate ๋ฐ์ thread๊ฐ ์คํ๋์ด lock์ release ํด์ค ๋๊น์ง ์คํ ๋ ์ ์๊ฒ ํด์ค๋ค.
์ค๋ ๋, ๋ฝ ๊ตฌ์กฐ์ฒด๋ฅผ ๋์ํํด๋ณด๋ฉด ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ๋ค.
๋จ์ด์์ ์ ์ ์๋ฏ์ด ์ฌ๋ฌ๋ฒ์ donation ์ด ์ผ์ด๋ ์ํฉ์ด๋ผ๊ณ ๋ณผ ์ ์๋ค. ์์ ์์์์ L ๊ฐ lock A, lock B ๋ผ๋ ๋ ๊ฐ์ง lock ์ ์ ์ ํ๊ณ ์๋ค๊ณ ํด๋ณด์. H ๊ฐ lock A ๋ฅผ, M ์ด lock B ๋ฅผ ๊ฐ๊ฐ ์์ฒญํ์์ ๋, L ์ ์์ ์ด ๊ฐ์ง๊ณ ์๋ lock ์ ์์ฒญํ ๋ชจ๋ ์ค๋ ๋์๊ฒ priority ๋ฅผ ์๋๋ฐ๊ณ , ์ด ์ค ๊ฐ์ฅ ๋์ priority ๋ฅผ ์ผ์์ ์ผ๋ก ์์ ์ priority ๋ก ๊ฐ๋๋ค. ๊ทธ๋ฆผ์ผ๋ก ๋ณด๋ฉด ์๋์ ๊ฐ๋ค.
์ด ์ํฉ์์ ์ค๋ ๋, ๋ฝ ๊ตฌ์กฐ์ฒด๋ฅผ ๋์ํํด๋ณด๋ฉด ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ๋ค.
๊ทธ๋ฆผ์์ ๋ณผ ์ ์๋ฏ์ด H ๊ฐ lock B ๋ฅผ ์ป๊ธฐ ์ํด M ์๊ฒ priority donation ์ ํํ๊ณ M ์ lock A ๋ฅผ ์ป๊ธฐ ์ํด L ์๊ฒ priority donation ์ ํํ๋ ๊ฒ ์ฒ๋ผ, ์ฌ๋ฌ๋ฒ์ ๋จ๊ณ์ donation ์ด ์ผ์ด๋๋ ์ํฉ์ด๋ค.
์ด๋ donation์ H๋ถํฐ ๋ฐ์ํด์ M, L ๋ชจ๋ H์ priority๋ฅผ donate ๋ฐ์ ์์ฐจ์ ์ผ๋ก lock์ ํด์ํด thread H๊ฐ ์ ์์ ์ผ๋ก lock์ accquire ํ ์ ์๊ฒ ํด์ค๋ค.
Priority donation์ ์ํด thread.h์ thread ๊ตฌ์กฐ์ฒด์ ์ถ๊ฐ์ ์ธ ๋งด๋ฒ๋ฅผ ์ ์ธํด์ค๋ค.
...
/* priority donation */
/* priority๋ฅผ ์๋ ๋ฐ๊ณ ๋ฐํํ๊ณ ๋์ ์๋ priority๋ฅผ ๋ณต์ํ๊ธฐ ์ํด ๊ธฐ๋ก*/
int init_priority;
/* thread๊ฐ ํ์ฌ ์ป๊ธฐ ์ํด ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ lock์ ์ฃผ์๋ก ์ค๋ ๋๋ ์ด lock ์ด release ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค. */
struct lock *wait_on_lock;
/* ์์ ์๊ฒ priority ๋ฅผ ๋๋์ด์ค thread๋ค์ ๋ฆฌ์คํธ์ด๊ณ */
struct list donations;
/* donations ๋ฆฌ์คํธ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ element ๋ก thread ๊ตฌ์กฐ์ฒด์ ๊ทธ๋ฅ elem ๊ณผ ๊ตฌ๋ถํ์ฌ ์ฌ์ฉํ๋๋ก ํ๋ค. */
struct list_elem donation_elem;
...
์๋กญ๊ฒ ์ถ๊ฐ๋ ๋งด๋ฒ๋ค์ธ ๋งํผ ์ด๊ธฐํ ์์ผ์ค์ผํ๋ค. init_thread() ์์.
/* thread/thread.c */
static void
init_thread (struct thread *t, const char *name, int priority)
{
...
t->init_priority = priority;
t->wait_on_lock = NULL;
list_init (&t->donations);
...
}
์ด ํจ์๋ ์์ ์ priority ๋ฅผ ํ์ํ lock ์ ์ ์ ํ๊ณ ์๋ ์ค๋ ๋์๊ฒ ๋น๋ ค์ฃผ๋ ํจ์์ด๋ค. ํ ๊ฐ์ง ์ฃผ์ํ ์ ์, nested donation ์์ ์ดํด๋ณธ ๊ฒ์ฒ๋ผ ํ์์ ์ฐ๊ฒฐ๋ ๋ชจ๋ ์ค๋ ๋์ donation ์ด ์ผ์ด๋๋ค๋ ๊ฒ์ด๋ค.
void
donate_priority (void) {
int depth;
struct thread *cur = thread_current ();
/* Nested donation ์ํฉ์ ๋๋นํด for๋ฌธ์ ๋๋ฆฐ๋ค */
for (depth = 0; depth < 8; depth++){
/* lock์ ์ป๊ธฐ ๊ธฐ๋ค๋ฆฌ๋ thread๊ฐ ์๋ ๊ฒฝ์ฐ breakํ๋ค. */
if (!cur->wait_on_lock) break;
/* ์ผ ๊ฒฝ์ฐ ์ต์์ priority๋ฅผ donate ํด์ค๋ค. */
struct thread *holder = cur->wait_on_lock->holder;
holder->priority = cur->priority;
cur = holder;
}
}
donations ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉฐ ํ์ฌ thread์๊ฒ priority๋ฅผ ๋น๋ ค์ค thread๋ค์
donation ๋ฆฌ์คํธ์์ ์ ๊ฑฐํด์ฃผ๋ ํจ์. ๋ค๋ง ํ์ฌ releaseํ๊ณ ์๋ lock ๋๋ฌธ์
donateํ thread๋ง ํด๋น๋๋ค.
/* thread/thread.c */
/* donations ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉฐ ํ์ฌ thread์๊ฒ priority๋ฅผ ๋น๋ ค์ค thread๋ค์
donation ๋ฆฌ์คํธ์์ ์ ๊ฑฐํด์ฃผ๋ ํจ์. ๋ค๋ง ํ์ฌ releaseํ๊ณ ์๋ lock ๋๋ฌธ์
donateํ thread๋ง ํด๋น๋๋ค. */
void
remove_with_lock (struct lock *lock) {
struct list_elem *e;
struct thread *cur = thread_current ();
/* donation ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉฐ */
for (e = list_begin (&cur->donations); e != list_end (&cur->donations); e = list_next (e)){
struct thread *t = list_entry (e, struct thread, donation_elem);
/* ์ธ์๋ก ๋ฐ์ lock์ ์ํด์ donate๋ฅผ ํ ๊ฒฝ์ฐ๋ผ๋ฉด */
if (t->wait_on_lock == lock)
list_remove (&t->donation_elem);
}
}
donation ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ ๊ฒฝ์ฐ๋ nested donation์ด ๋ฐ์ํ ๊ฒฝ์ฐ ๋๋ฌธ์ด๋ค.
ํ์ฌ thread์ priority๋ฅผ ์๋๋๋ก ๋ณต๊ตฌ์ํค๊ฑฐ๋, ์์ง donations ๋ฆฌ์คํธ๊ฐ ๋น์ด์์ง ์๋ค๋ฉด
(์์ง ๋์๊ฒ priority๋ฅผ ๋น๋ ค์ค thread๋ค์ด ๋จ์์๋ค๋ฉด) ๊ทธ์ค ๊ฐ์ฅ ๋์ priority๋ก ์ฌ์ค์ .
/* thread/thread.c */
/* ํ์ฌ thread์ priority๋ฅผ ์๋๋๋ก ๋ณต๊ตฌ์ํค๊ฑฐ๋, ์์ง donations ๋ฆฌ์คํธ๊ฐ ๋น์ด์์ง ์๋ค๋ฉด
(์์ง ๋์๊ฒ priority๋ฅผ ๋น๋ ค์ค thread๋ค์ด ๋จ์์๋ค๋ฉด) ๊ทธ์ค ๊ฐ์ฅ ๋์ priority๋ก ์ฌ์ค์ . */
void
refresh_priority (void) {
struct thread *cur = thread_current ();
cur->priority = cur->init_priority;
/* donate ๋ฐ์ priority๊ฐ ์์ง ๋จ์์๋ค๋ฉด */
if (!list_empty (&cur->donations)) {
list_sort (&cur->donations, thread_compare_donate_priority, 0);
/* ๊ทธ์ค ๊ฐ์ฅ ๋์ priority๋ฅผ ํ์ฌ thread์ priority๋ก ์ค์ */
struct thread *front = list_entry (list_front (&cur->donations), struct thread, donation_elem);
if (front->priority > cur->priority)
cur->priority = front->priority;
}
}
lock์ ๋ฐ์์ค๋, ์์ฒญํ๋ ํจ์์ ๋๋ค. ๋ค๋ฅธ thread๊ฐ key๋ฅผ ๋ณด์ ์ค์ผ ๊ฒฝ์ฐ lock์ ๋ฐ์์ฌ ์ ์์ ๋๊น์ง (key๊ฐ release ๋ ๋๊น์ง) thread๋ฅผ sleep/block ์ํต๋๋ค.
donate_priority()๊ฐ ์ฌ์ฉ๋์์ต๋๋ค.
lock_acquire (struct lock *lock) {
ASSERT (lock != NULL);
ASSERT (!intr_context ());
ASSERT (!lock_held_by_current_thread (lock));
/* ==================== project1 Priority Donation ==================== */
struct thread *cur = thread_current();
/* ์์์ lock์ด ํ์ฌ thread์๊ฒ ์๋์ง๋ฅผ ์ด๋ฏธ assertํ๊ธฐ์ holder๊ฐ ์๋ค๋ฉด ๋ค๋ฅธ thread๋ค.
๋ฐ๋ผ์ donation์ ํตํด lock holder thread๊ฐ ์คํ๋ ์ ์๊ฒ ํด์ค๋ค. */
if (lock->holder) {
cur->wait_on_lock = lock;
/* lock holder์ donation ๋ฆฌ์คํธ์ ํ์ฌ thread๋ฅผ ๊ธฐ๋กํด์ค๋ค. Priority ์์ผ๋ก */
list_insert_ordered(&lock->holder->donations, &cur->donation_elem,
thread_compare_donate_priority, NULL);
donate_priority();
}
sema_down (&lock->semaphore);
cur->wait_on_lock = NULL;
lock->holder = cur;
/* ============
ํ์ฌ thread๊ฐ ๋ค๊ณ ์๋ lock์ ๋ฐํํ๋ ํจ์.
remove_with_lock(), refresh_priority๊ฐ ์ฌ์ฉ๋์์ต๋๋ค.
/* Releases LOCK, which must be owned by the current thread.
This is lock_release function.
An interrupt handler cannot acquire a lock, so it does not
make sense to try to release a lock within an interrupt
handler. */
void
lock_release (struct lock *lock) {
ASSERT (lock != NULL);
ASSERT (lock_held_by_current_thread (lock));
/* ==================== project1 Priority Donation ==================== */
remove_with_lock (lock);
refresh_priority ();
/* ==================== project1 Priority Donation ==================== */
lock->holder = NULL;
sema_up (&lock->semaphore);
}
ํ์ฌ thread๊ฐ lock, donation๊ณผ ๊ด๊ณ์์ด thread_set_priority ํจ์๋ฅผ ํธ์ถํจ์ผ๋ก ์์ ์ priority๊ฐ ๋ณ๊ฒฝ๋ ์ ์๋ค. ์ด ๊ฒฝ์ฐ ํํ init_priority์ฆ ์๋ณธ priority๋ฅผ ๊ฐฑ์ ํด์ฃผ์ด์ผํ๋ค. ๋ํ donations ๋ฆฌ์คํธ๋ค์ ์๋ ์ค๋ ๋๋ค๋ณด๋ค priority ๊ฐ ๋์์ง๋ ๊ฒฝ์ฐ๊ฐ ์๊ธธ ์ ์๋ค. ์ด ๊ฒฝ์ฐ priority ๋ donations ๋ฆฌ์คํธ ์ค ๊ฐ์ฅ ๋์ priority ๊ฐ ์๋๋ผ ์๋ก ๋ฐ๋ priority ๊ฐ ์ ์ฉ๋ ์ ์๊ฒ ํด์ผ ํ๋ค.
/* thread/thread.c */
/* Sets the current thread's priority to NEW_PRIORITY. */
void
thread_set_priority (int new_priority) {
/* ==================== project1 Prioirity Scheduling ==================== */
thread_current ()->init_priority = new_priority;
// thread_current ()->priority = new_priority;
refresh_priority ();
test_max_priority();
/* ==================== project1 Prioirity Scheduling ==================== */
}
https://firecatlibrary.tistory.com/58?category=875424
pass tests/threads/alarm-single
pass tests/threads/alarm-multiple
pass tests/threads/alarm-simultaneous
pass tests/threads/alarm-priority
pass tests/threads/alarm-zero
pass tests/threads/alarm-negative
pass tests/threads/priority-change
pass tests/threads/priority-donate-one
pass tests/threads/priority-donate-multiple
pass tests/threads/priority-donate-multiple2
pass tests/threads/priority-donate-nest
pass tests/threads/priority-donate-sema
pass tests/threads/priority-donate-lower
pass tests/threads/priority-fifo
pass tests/threads/priority-preempt
pass tests/threads/priority-sema
pass tests/threads/priority-condvar
pass tests/threads/priority-donate-chain
FAIL tests/threads/mlfqs/mlfqs-load-1
FAIL tests/threads/mlfqs/mlfqs-load-60
FAIL tests/threads/mlfqs/mlfqs-load-avg
FAIL tests/threads/mlfqs/mlfqs-recent-1
pass tests/threads/mlfqs/mlfqs-fair-2
pass tests/threads/mlfqs/mlfqs-fair-20
FAIL tests/threads/mlfqs/mlfqs-nice-2
FAIL tests/threads/mlfqs/mlfqs-nice-10
FAIL tests/threads/mlfqs/mlfqs-block
7 of 27 tests failed.