6. 프로세스 동기화 & 상호 배제 (7) - Monitor

728x90
반응형

출처 : https://www.youtube.com/watch?v=AnYN-kbCbRI&list=PLBrGAFAIyf5rby7QylRc6JxU5lzQ9c4tN&index=18

 

 

 

 

 

이전까지 배운 솔루션들은 Flexible 다양하게 적용이 가능하다는 장점이 있었다. 하지만 좀 복잡하다는 문제점이 있고, 에러가 발생할 가능성이 크다는 단점이 있다.

 

그래서 이번에는 우리가 사용하는 프로그래밍 언어 레벨에서 제공하는 솔루션인 "Monitor"를 알아보자.

 

 

High-level Mechanism

 

  • Monitor

 

  • Language-level constructs : 프로그래밍 언어가 Mutual Exclusion을 서포트한다.
  • Object-Oriented concept와 유사
  • 사용이 쉬움

 

 

Monitor

 

  • 공유 데이터와 Critical Section의 집합, 공유데이터(읽고 싶은 책)와 CS(책을 읽기 위한 연산을 수행하는 영역)를 모아놓은 하나의 방.
  • 한 번에 한 명만 들어올 수 있음
  • Conditional variable
    • wait(), signal() operations

 

 

모니터의 구조

 

  • Entry queue (진입 큐) : 한 명씩 CS 진입할 수 있도록 만들어주는 큐
    • 모니터 내의 procedure(=function) 수만큼 존재
  • Mutual exclusion : 프로그래밍 언어가 보장해 
    • 모니터 내에는 항상 하나의 프로세스만 진입 가능
  • Information hiding (정보 은폐)
    • 공유 데이터는 모니터 내의 프로세스만 접근 가능
  • Condition queue (조건 큐)
    • 모니터 내의 특정 이벤트를 기다리는 프로세스가 대기하는 대기
  • Signaler queue (신호제공자 큐) : 대기실에서 기다리는 프로세스에게 신호를 보내기 위해 잠깐 들어가는 공간
    • 모니터에 항상 하나의 신호제공자 큐가 존재
    • signal() 명령을 실행한 프로세스가 임시 대기

 

 

  • 자원 할당 문제
  • R_Available(=책) 라는 리소스가 1개 있다. 그러므로 한 번에 한 명만 사용할 수 있다.
  • entry queue for requestR() : 자원을 요청하는 function, 책을 대출하는 명령
  • entry queue for releaseR() : 자원을 반납하는 function, 책을 반납하는 명령
  • requestR() : 책을 대출하는 공간
  • releaseR() : 책을 반납하는 공간
  • condition queue R_Free : 리소스가 있을 때(=책을 빌릴 수 있을 때) 빌릴 수 있도록 조건을 확인하는 대기하는 대기실
  • signaler queue : condition queue에 있는 프로세스를 깨우는 공간

 

 

코드로 옮기면 위 그림과 같다.

 

대출

Procedure requestR() : 책을 대출하기위한 요청 메시지를 보낸다.

if (~R_available) : 책이 있는지 없는지 확인한다.

R_free.wait() : 만약 책이 없으면 기다린다.

R_Available <- False : 만약 책이 있으면 R_Available을 False로 변경해서 다른 사람이 빌리지 못하도록 만든다.

 

반납

procedure releaseR() : 책을 반납하기 위한 메시지를 보낸다.

R_Available <- True : 책을 반납하면 다른 사람이 빌릴 수 있도록 R_Available을 True로 변경한다.

R_free.signal() : 책을 빌릴 수 있으니까 대기실에 있던 사람에게 책을 빌려도 된다 signal을 보낸다.

 

 

 

  • 자원 할당 시나리오. Initial monitor state
    • 자원 R 사용 가능
    • 모니터 안에 프로세스 없음

최초의 자원 R은 모니터 밖에 존재한다. R_Available(자원이 존재하는가?)는 1(True)로 시작한다.

 

 

  • 자원 할당 시나리오 Monitor state 1
    • 프로세스 Pj가 모니터 안에서 자원 R을 요청

entry queues for requestR()에 프로세스 Pj가 책을 빌리러 왔다. 모니터 안에는 아무도 없으므로 Pj는 모니터 안의 requestR()에 들어온다. 프로세스 Pj가 책을 빌려가므로 R_Available은 0(=False)로 변경된다. 그리고 모니터 밖으로 나와서 책(=자원 R)을 본다.

 

이 상황에서 entry queues for requestR()에 Pk, Pm이 도착했다고 해보자. Pj는 모니터 밖에서 R을 사용하고 있으므로 모니터 안에는 프로세스가 존재하지 않으므로 Pk는 모니터 안의 requestR()에 진입한다. 하지만 R_Available이 0이므로 Pk는 condition queue R_Free 라는 대기실에서 대기하게 된다. Pm도 Pk와 동일한 방식을 거쳐서 condition queue에서 대기하게 된다.

 

 

  • 자원 할당 시나리오 Monitor state 2
    • 자원 R이 Pj에게 할당 됨
    • 프로세스 Pk가 R 요청, Pm 또한 R 요청

프로세스 Pj가 작업을 마치면 자원 R을 반납하기 위해 entry queues for releaseR()로 들어오게 된다. 모니터 안에는 아무도 없으니 바로 releaseR()로 들어오고, R_Available을 1로 바꾼다. 그리고 signaler queue로 들어와서 condition queue에 있는 Pk를 깨운다.

 

condition queue에서 대기하던 프로세스 Pk는 requestR()로 들어와서 R_Available을 0으로 바꾸고 자원 R을 사용한다.

 

 

  • 자원 할당 시나리오 Monitor state 3
    • Pj가 R 반환
    • R_Free.signal() 호출에 의해 Pk가 Wake up

 

 

 

  • 자원 할당 시나리오 Monitor state 4
    • 자원 R이 Pk에게 할당 됨
    • Pj가 모니터 안으로 돌아와서, 남은 작업 수행

프로세스 Pk가 자원 R을 사용하기 위해 모니터에서 나가면 signaler queue 에 있던 Pj는 다시 releaseR()로 돌아와 남은 마무리 작업을 수행하고 모니터 밖으로 나간다.

 

 

 

  • 사이즈가 N인 circular queue를 사용하는 Producer-Consumer problem

 

  • entry queue for fillBuf() : 물건을 넣는 프로세스. Producer가 호출
  • entry queue for emptyBuf() : 물건을 빼가는 프로세스. Consumer가 호
  • bufHasData : Consumer가 물건이 없으면 기다리는 공간. 즉, Consumer의 condition queue
  • bufHasSpace : Producer가 물건이 없으면 기다리는 공간. 즉, Producer의 condition queue
  • validBufs : 물건의 갯수

 

 

Procedure fillBuf(data : message) : producer가 물건을 채우기 위해 공간이 있는지 확인한다.

if (validBufs = N) then bufHasSpace.wait() : 만약 물건의 수가 N이라면(공간이 없다면), bufHasSapce에서 대기한다.

buffer[in] <- data : 만약 공간이 있다면(혹은 없었는데 생겼다면) buffer[in]에 데이터를 쌓는다.

validBufs <- validBufs + 1 : 물건을 하나 놓았으니 물건 수를 1 증가시킨다.

in <- (in + 1) mod N : 물건을 넣을 공간 in 을 업데이트 한다.

bufHasData.signal() : 내가 물건을 놓았으니, 혹시 물건을 기다리는 Consumer가 있으면 wake up 시킨다.

 

Procedure emptyBuf : Consumer가 물건을 가져가기 위해 물건이 있는지 확인한다.

if (validBufs = 0) then bufHasData.wait() : 만약 물건이 0개라면, bufHasData에서 대기한다.

data <- buffer[out] : 물건이 있다면 혹은 생겼다면, data에 buffer[out]에 있는 것을 저장한다. 즉, 물건을 꺼낸다.

validBufs <- validBufs - 1 : 물건을 꺼냈으니, 물건의 갯수를 1 감소시킨다.

out <- (out + 1) mod N : 물건을 꺼낼 공간 out 을 업데이트 한다.

bufHasSpace.signal() : 내가 물건을 꺼냈으니, 혹시 공간을 기다리는 Producer가 있으면 wake up 시킨다.

 

 

  • Reader-Writer Problem
    • reader / writer 프로세스들간의 데이터 무결성 보장 기법
    • writer 프로세스에 의한 데이터 접근 시에만 상호 배제 및 동기화 필요함

 

  • 모니터 구성
    • 변수 2개
      • 현재 읽기 작업을 진행하고 있는 reader 프로세스의 수
      • 현재 writer 프로세스가 쓰기 작업을 진행 중인지 표시
    • condition queue 2개
      • reader / writer 프로세스가 대기해야 할 경우에 사용
    • Procedure 4개
      • reader(writer) 프로세스가 읽기(쓰기) 작업을 원할 경우에 호출, 읽기 (쓰기) 작업을 마쳤을 때 호출

 

 

 

  • Dining philosoper problem
    • 5명의 철학자
    • 철학자들은 생각하는 일, 스파게티 먹는 일만 반복함
    • 공유 자원 : 스파게티, 포크
    • 스파게티를 먹기 위해서는 좌우 포크 2개 모두 들어야 함. 하지만 포크는 총 5개가 존재
    • 철학자 = Process, 포크 = shared data

 

 

pickup(i) : 스파게티를 먹기 위해 포크를 든다.

eating : 스파게티를 먹는다.

putdown(i) : 스파게티를 먹고 나서 포크를 내려놓는다.

thinking : 생각한다. 대기실에서 대기한다.

 

 

procedure pickup(me) : 포크를 2개 들어야 한다. 이 연산은 한 명만 할 수 있다. 왜냐하면 이 밑에 있는 것들은 모니터 안에서 동작하기 때문이다.

if (numForks[me] != 2) then ready[me].wait() : 포크를 2개 들 수 있는지 확인한다. 만약 들 수 없으면 자신의 ready(=condition queue)에서 기다린다.

numForks[right(me)] <-numForks[right(me)] - 1

numForks[left(me)] <- numForks[left(me)] - 1 : 만약 내가 포크를 2개 들 수 있다면, 내 왼쪽과 오른쪽에 있는 철학자가 사용할 수 있는 포크의 수가 1개씩 줄어든다.

 

Procedure putdown(me) : 스파게티를 먹고 포크를 내려놓는다.

numForks[right(me)] <- numForks[right(me)] + 1

numForks[left(me)] <- numForks[left(me)] + 1 : 내 오른쪽과 왼쪽에 있는 철학자가 사용할 수 있는 포크의 수가 1개씩 늘어난다.

if (numForks[right(me)] = 2) then ready(right(me)).signal()

if (numForks[left(me)] = 2) then ready(left(me)).signal() : 내 왼쪽과 오른쪽의 철학자가 ready에서 대기하고 있고, 사용할 수 있는 포크가 2개가 되었으면 wake up 시켜준다.

 

 

  • numForks : 철학자들이 사용가능한 포크의 수
  • condition queues : 각 철학자들이 자기만의 대기실을 가지고 있다. 내가 포크를 쓸 수 있을 때까지 condition queue에서 대기한다.

 

 

Monitor

 

  • 장점
    • 사용이 쉽다
    • Deadlock 등 error 발생 가능성이 낮다.
  • 단점
    • 지원하는 언어에서만 사용 가능
    • 컴파일러가 OS를 이해하고 있어야 한다.
      • Critical Section 접근을 위한 코드 생성
728x90
반응형