본문 바로가기
KraftonJungle2기/회고

[WIL] Pintos 1주차 - Threads (주간공유)

by SooooooooS 2023. 6. 1.
728x90

 

1. 일정 계획

✅ 05.25

  • 개인 노트북에 우분투 환경 설정
  • 대략적인 일정 조율
  • 개인 이론 공부

✅ 05.26

  • git book 읽기
  • os (thread, processor 등) 관련 개념 공부 및 공유

✅ 05.27

  • Alarm 구현 1일차
  • thread.c timer.c 코드 분석

✅ 05.28

  • Alarm 구현 2일차

✅ 05.29

  • Priority 구현 1일차
  • synch.c 코드 분석

✅ 05.30

  • Priority 구현 2일차

✅ 05.31

  • Priority 구현 3일차

2. 주요 학습

synch.c - lock_acquire()
: donation list 저장방식의 차이

1. donate 가능한 모든 후보자들 저장

모든 waiters의 요소들을 donation list에 저장하기

void lock_acquire (struct lock *lock) {
    ASSERT (lock != NULL);
    ASSERT (!intr_context ());
    ASSERT (!lock_held_by_current_thread (lock));

    struct thread *curr = thread_current();
    if (lock->holder != NULL) { // 이미 lock을 점유하고 있을 경우
        curr->wait_on_lock = lock;
        list_insert_ordered(&lock->holder->donations, &curr->donation_elem, donation_sort, NULL);
        donate_priority(); // 우선순위 조정
    }
    sema_down (&lock->semaphore);
    curr->wait_on_lock = NULL;
    lock->holder = curr;
}
  • 장점 : donation list에 삽입하는 과정이 간단하다.
  • 단점 : lock_release()시 donation list에서 특정 lock에 대한 모든 waiters삭제해야한다.

2. waiters의 최댓값만 저장

waiters의 최댓값만 donation list에 저장하기

void lock_acquire(struct lock *lock)
{
	ASSERT(lock != NULL);
	ASSERT(!intr_context());
	ASSERT(!lock_held_by_current_thread(lock));

	struct thread *curr = thread_current();

	// if the lock is not available
	if (lock->holder != NULL) { 
		curr->wait_on_lock = lock;
		//lock을 잡고있는 스레드의 원래 우선순위보다 큰 경우
		if (curr->priority > lock->holder->origin_priority) {
			// waiters의 값이 처음 입력되는경우 = donation list에도 현재 lock에 대한 값이 없다.
			if (list_empty(&lock->semaphore.waiters)) {
				list_push_back(&lock->holder->donations, &curr->donation_elem); // add current thread into donation list.
			} 
			//waiters에 값이 존재 = donation list에 현재 lock에 대한 값 존재
			// 현재 스레드의 우선순위가 waiters의 가장 높은 우선순위보다 높으면 donation 안에 값을 바꿔줘야한다.
			else if (list_entry(list_front(&lock->semaphore.waiters), struct thread, elem)->priority < curr->priority) {
				struct list_elem *e;
				//donation list를 탐색
				for (e = list_begin(&lock->holder->donations); e != list_end(&lock->holder->donations); e = list_next(e)) {
					struct thread *t = list_entry(e, struct thread, donation_elem);
					// 받아온 락이 wait_on_lock일경우
					if (lock == t->wait_on_lock && &t->donation_elem != NULL) {
						list_remove(&t->donation_elem);
						// insert current thread in the donation list before the thread with lower priority
						list_insert_ordered(&t->donations, &curr->donation_elem, donation_sort, NULL);
						break;
					}
                    else{
                    	list_insert_ordered(&t->donations, &curr->donation_elem, donation_sort, NULL);
                        break;
                    }
				}
			}
			donate_priority();
		}
	}
	sema_down(&lock->semaphore);
	lock->holder = curr;
	curr->wait_on_lock = NULL;
}
  • 장점 : lock_release()시 donation list에서 특정 lock에 대한 하나의 값만 삭제하면 된다.
  • 단점 : 삽입시 여러 조건을 생각해야한다.

3. 회고

커널 연결리스트의 구조

  • elem : 연결 리스트에서 각 요소를 가리키는 포인터 역할
  • 연결 리스트의 다음 요소와 이전 요소를 가리키는 포인터(next와 prev)가 포함
  • 즉, 스레드 내 멤버인 list_elem이 실제로 list에 줄 서있는 요소

1. 오류 코드

list_remove(find(&lock->holder->donations, list_head(&lock->semaphore.waiters)));

2. 맞은 코드

list_remove(&t->donation_elem);

 

 🗒️ 이번 주차 후기
  코드를 짜는데 있어서 너무 많은 것을 한번에 생각하면서 비효율적인 일주일을 보낸 것같다.
순서대로 하나씩 했더라면 훨씬 효율적이었을 것 같았다. 다음 주차에는 개념정리를 좀 더 확실하게 하여 구현 순서를 이해하면서 코드를 짤 수 있도록 해야겠다.
  지금 당장 무엇을 해야하는지를 아는 것이 가장 중요하다고 느껴진 주차였다. 
또한 다음주차에는 기록을 좀 더 해두어야 겠다.
728x90