Project 1 - Threads

qwbsy·2021년 12월 15일
0

pintOS는 싱글 쓰레드로 작동하는 OS환경인데 그렇기 때문에 가장 먼저 쓰레드가 어떤 식으로 작동하는지를 알아갈 수 있는 주제가 나온 것 같다. 주어진 코드에는 쓰레드가 생성되고 실행되는 등의 기본적인 기능들이 구현되어 있어서 간단한 흐름들을 파악할 수 있었고 우리가 구현해야 할 코드들은 정책과 관련된 것들이었다.

Alarm Clock

기존 코드는 쓰레드를 깨우는 방식이 정말 비효율적이다. 시간의 흐름이 생길 때마다 깨어날 시간을 체크해서 맞을 때까지 반복한다. 이럴 거면 차라리 재우지 않는 게 낫지 않나 싶기도 하다.
이를 해결하기 위해서 thread 구조체에 일어날 시간을 저장할 수 있게 하고, sleep_list를 만들어서 다음 일어날 쓰레드가 있는 시간이 되면 해당하는 쓰레드들을 깨우는 방식을 적용한다.

Priority Scheduling

현재는 깨어 있는 쓰레드들이 순서대로 실행되고 있다. 이제는 각 쓰레드들에 우선순위에 따라 그 순서를 조정할 수 있도록 해줘야 한다. 먼저, 각 쓰레드에 우선순위 값을 정할 수 있도록 해야하고 정해진 값을 기준으로 ready_list가 정렬되어야 한다. ready_list에 쓰레드가 추가되는 상황은 다음과 같다.

  1. 새로운 쓰레드가 생성될 때
  2. 자고 있던 쓰레드가 깨어날 때
  3. 현재 쓰레드가 CPU를 양보할 때

3번을 보면 알 수 있겠지만 우선순위 스케줄링이 제대로 일어나려면 우선순위가 높은 쓰레드가 ready_list에 있을 땐 현재 쓰레드가 양보해줘야 한다. 그러기 위해서 ready_list의 가장 우선순위가 높은 쓰레드를 관리해줘야 하는데 그 값이 더 높아지면 현재 쓰레드와 우선순위를 비교하는 작업을 실행한다. 1,2번의 경우이거나 ready_list에 있던 쓰레드의 우선순위가 높아질 때 또는 현재 쓰레드의 우선순위가 낮아질 때, 이 비교작업이 실행될 가능성이 있다.

Synchronization

쓰레드들이 자기 작업을 완전히 마치지 않고 다른 쓰레드의 작업이 시작된다면 동시성 이슈가 발생할 수 있다. pintOS는 단일 프로세스, 단일 쓰레드로 실행되고 있기 때문에 동시성 이슈가 발생하면 공유자원 사용하는 것을 관리해줄 필요가 있다. 여기서 세마포어와 락 등의 개념이 있는데 다음 내용을 설명하기 위해 특정 자원에 대해 락(lock)을 가지고 있는 쓰레드가 있으면 해당 자원을 쓰려는 쓰레드는 기다려야 한다는 정도로 알아두자.

우선순위에 따라 쓰레드가 실행될 때, lock 때문에 그 우선순위가 제대로 반영되지 않는 경우가 생길 수 있다. lock을 가진 쓰레드가 lock을 풀어줄 때까지 기다리는 쓰레드가 있을텐데 기다리는 쓰레드보다 우선순위가 낮음에도 lock을 가진 쓰레드보단 높아서 먼저 실행하게 된다. 이런 경우가 계속해서 발생하면, 기다리는 쓰레드의 우선순위가 높음에도 불구하고 lock을 풀어주는 상황의 우선순위가 낮아서 계속 실행되지 않는 기아(Starvation) 현상이 나타날 수 있다.
이 문제를 해결하기 위해선 lock을 가진 쓰레드에게 기다리고 있는 쓰레드의 높은 우선순위를 빌려줘야 한다. 그렇게 되면 기다리는 쓰레드의 우선순위보다 낮은 쓰레드보다 lock을 풀어주는 상황을 우선하게 되기 때문에 원하는 우선순위대로 실행되게 할 수 있다.

Advanced Scheduler

우선순위 스케줄링이 작동하도록 구현해놨으니 실제 우선순위를 어떻게 적용할지에 대한 것도 고민해봐야 한다. Multi-Level Feedback Queue Scheduler(mlfqs)의 구성인 4.4BSD 스케줄러를 간단히 살펴보자.
4.4BSD 스케줄러

0개의 댓글