[기술면접] 운영체제(2) : 세마포어를 활용한 대표적인 Critical Section 문제 해결

Alice·2023년 8월 31일
0
post-thumbnail

Producer-Consumer Problem

여러개의 생산자 프로세스소비자 프로세스가 있다. 생산자 프로세스는 공유 버퍼에 데이터를 만들어 집어넣는다.

생산자 프로세스들이 동시에 하나의 버퍼에 데이터를 추가하면 안되기때문에 데이터를 입력할 때 공유데이터에 락을 걸고 작업을 실행한다. 소비자 프로세스 역시 마찬가지로 하나의 버퍼에서 동시에 자원을 소비하면 안되기 때문에 락을 활용하여 작업한다. 이 문제를 세마포어를 활용해 해결할 수 있다.


버퍼가 가득 찬 상태에서 다른 생산자가 또 데이터를 추가하려한다면 시도할 수 없다. 소비자 프로세스가 데이터를 꺼내서 빈 버퍼가 발생하면, 이를 획득하여 데이터를 추가해야한다.

세마포어 변수 Full = 0Empty = n 가 있고, 락을 표현하기 위한 세마포어 변수 Mutex 가 있다.

생산자

  1. 비어있는 버퍼가 있는지 확인 (없으면 기다림)
  2. 빈 버퍼가 있으면 공유 데이터에 락을 건다.
  3. 빈 버퍼에 데이터 입력 및 버퍼 조작
  4. 락을 푼다.
  5. Full 증가

소비자

  1. 내용이 있는 버퍼가 있는지 확인 (없으면 기다림)
  2. 내용이 있는 버퍼가 있다면 공유 데이터에 락을 건다.
  3. 내용이 있는 버퍼에서 데이터를 꺼내고 버퍼 조작
  4. 락을 푼다.
  5. Empty 증가



Readers-Writers Problem

자원의 읽기 작업은 동시에 여럿이 해도 상관없지만, 쓰기 작업 도중에는 다른 프로세스가 접근해서는 안되는 경우를 뜻한다. 또한 읽기 작업 도중에는 쓰기 작업이 실행될 수 없다.

readCount 라는 변수를 통해서 읽기 작업을 설정할 수 있다. 가장 처음 읽기 작업을 하러 온 프로세스가 readCount = 1 로 설정하고 락을 걸어두면, 그 다음 프로세스들은 이 작업을 건너뛰고 읽기 작업을 수행할 수 있다.

하지만 readCount 라는 변수 또한 공유데이터고, 모든 프로세스들이 절차없이 값을 변경하면 문제가 생길 수 있다. 따라서 readCount 변수를 위한 세마포어인 mutex 를 활용한다.

모든 읽기 작업이 끝나고 readCount = 0 이 되면, DB 의 락을 풀어줘서 쓰기 작업 대기중인 프로세스가 있다면 역할을 수행할 수 있게 해준다. DB 에 락을 걸고 풀기 위한 세마포어로 db 라는 변수를 사용했다.

읽기 작업이 모두 끝나기전에는 쓰기 작업이 불가능하기 때문에, 읽기 작업이 계속 들어오는 경우 Starvation 문제가 발생할 수 있다.



Dining-Philosophers Problem

철학자가 밥을 먹기 위해서는 양 옆의 젓가락을 모두 들어야한다. 하지만 양 옆의 철학자들이 해당 젓가락을 번갈아가면서 잡아들고 가운데 위치한 철학자가 두 개의 젓가락을 모두 잡을 수 있는 기회를 주지 않는다면, 철학자는 굶어 죽게된다.

이 역시 세마포어를 통해 해결할 수 있지만, 데드락을 야기할 수 있다. 모든 철학자가 왼쪽 젓가락을 집어들고있다면, 오른쪽 젓가락은 아무도 들 수 없고 전부 굶어죽게된다.

해결방안

  1. 5명중 4명의 철학자만이 테이블에 동시에 앉을 수 있도록 한다.
  2. 젓가락을 두 개 모두 잡을 수 있을 때에만 젓가락을 잡을 수 있게 한다.

위와 같은 해결방안들이 존재한다.

2번 에 해당하는 해결방안으로 코드를 재작성 할 수 있다.

양쪽 젓가락을 모두 들 수 있는지 여부를 저장하는 세마포어 변수 self 와 철학자들의 상태를 저장하는 변수 state 가 존재한다. 또한, 한 철학자가 다른 철학자의 state 를 변경할 수 없도록 하는 세마포어 변수 mutex 를 도입한다.






Monitor

세마포어에도 문제점이 많다.

  1. 코딩하기 힘들다.
  2. 정확성의 입증이 어렵다.
  3. 한번의 실수가 시스템에 치명적으로 작용한다.

모니터는 모니터 자체로 동시 접근을 허용하지 않기 때문에 프로그래머가 직접 을 걸 필요가 없다는 장점이 있다. 모니터는 모니터 내부에 공유 데이터에 대한 선언이 있고, 공유 데이터에 접근하기 위한 프로시저를 모니터 내부 함수로 구현한다.

모니터 내에서는 한번에 하나의 프로세스만이 활동할 수 잇다. 프로세스가 모니터 안에서 대기할 수 있도록 하기 위해 모니터에서는 WaitSignal 이라는 Condition Variable 을 사용한다.

해당 프로세스가 오래 대기해야하는 경우 X.wait() 메소드를 호출하면 해당 프로세스는 X 라는 Confition variable 뒤에서 줄을 서게된다. 반대로 잠들어있는 프로세스중 하나를 깨우라는 명령어는 X.signal() 이다.


생산자와 소비자 문제를 모니터를 활용하여 다시 해결하면 위와 같은 코드가 나온다. 락을 걸고 해제하는 코드의 작성이 사라졌다. 또한 Conditional Variable 인 fullempty 가 존재한다.

Conditional Variable 은 값을 가지지 않고, 자신의 큐에 프로세스를 매달아서 sleep 시키거나 wakeUp 하는 역할만 담당한다.

profile
SSAFY 11th

0개의 댓글