운영체제 7-4강 (동기화 문제 마지막 파트)

늘보·2021년 7월 6일
0

OS

목록 보기
16/25

→ Open in Slid

  • 본 글은 이전에 사용하던 영상 강의 필기 앱인 'Slid'에서 필기 했던 내용을 Velog로 옮긴 내용입니다.
  • 본 글은 이화여대 반효경 교수님 2017학년도 1학기 운영체제 강의를 기반으로 작성되었습니다.
  • 강의 링크 : http://www.kocw.net/home/search/kemView.do?kemId=1226304

지금까지 Semaphore에 대한 얘기를 주구장창 했다. 그런데 Semaphore의 문제점은 있다. 구현도 어렵고, 실수 하면 시스템이 완전히 무너진다. 또한 Semaphore를 이용하여 프로그래밍 했을 때 어디에 P연산과 V연산이 들어가야 하는지 정확히 시스템이 작동되는지 검증하기가 굉장히 어렵다.

운영체제 7-4강 (동기화 문제 마지막 파트) image

그러면 이러한 동기화 문제를 해결함에 있어서 조금 더 쉬운 방법은 없을까 고민하다가 나온 것이 Monitor라는 개념이다.

Monitor

Monitor는 High-level Language에서 제공하는 동기화 수단이다. Semaphore에서는 공유 데이터 접근을 Semaphore가 책임지지 않았고 실제로 동기화 문제는 프로그래머가 처리해야 했다. 공유 데이터에 접근하기 전에 Lock을 프로그래머가 걸어야 하는 등 통제를 프로그래머가 직접 하였다. 반면 Monitor는 객체 지향 프로그래밍에서의 Class 개념과 비슷하게 설계된다. 한 객체에 공유하고 있는 shared variable이 존재하며 멤버 함수를 통해 intruction을 제공하며 이 instruction들을 통해 shared variable에 대한 모든 접근을 통제한다. 그 처리를 entry queue를 통해 한다. 어떤 프로세스가 멤버 연산을 통해 공유 데이터에 접근하고 있을 때 CPU를 빼앗기고 다른 프로세스가 공유 데이터에 접근하려고 할 때 entry queue에 집어 넣어 접근 자체를 막아 버리는 식으로 통제하는 것이다.

운영체제 7-4강 (동기화 문제 마지막 파트) image

운영체제 7-4강 (동기화 문제 마지막 파트) image

그러면 어떻게 그것을 처리하는지 조금 더 자세히 들여다 보자.

우선 모니터 내에서는 한 번에 하나의 프로세스만 활동이 가능하다. 그렇기 때문에 여러 프로세스들이 모니터 내에 있는 공유 데이터에 접근하는 것을 통제하기 위해 condition variable(queue의 역할을 한다.)을 사용한다. 이것은 Semaphore와 비슷하다. 자원에 여분이 있을 때는 접근하게 하지만, 여유가 없을 때는 이 condition variable을 통해 차단하게 되며 앞서 말한 queue에 해당 프로세스를 집어 넣는 역할을 이 condition variable이 수행하는 것이다. 만약 x라는 자원에 여유가 없다면

x.wait()를 호출하고 이 함수를 호출한 프로세스는 queue에 들어가 잠들게 된다. 그리고 어떤 프로세스가 자원을 다 쓰고 나오면 x.signal()를 호출하고 이 signal()이 호출되면 아까 전에 잠들었던(suspend) 프로세스를 깨운다.

운영체제 7-4강 (동기화 문제 마지막 파트) image

Bounded-Buffer Problem (Monitor)

  Semaphore는 어떤 연산이 atomic하게 처리되는 것을 도와주어 이를 이용하여 동시 접근을 막는 것이고, Monitor는 원자적 연산을 지원하는 것이 아니라 애초에 한 번에 한 프로세스만 처리하는 방식으로 설계되어 여러 프로세스의 동시 접근을 막는다. 앞서 Semaphore로 동기화 문제를 해결했던 그 Bounded-Buffer, 생산자-소비자 문제로 돌아가서 이 문제를 Monitor로 해결해보자.

 먼저 monitor라는 타입의 bounded_buffer 객체가 있는데 이 객체 내부에는 공유하고 있는 버퍼가 N개 존재한다.

(int buffer[N])

그리고 condition variable은 Semaphore에서 자원의 개수를 Count했던 것과는 다르게 자원의 개수를 세지 않는다. 단순히 자원이 없을 때 프로세스를 재우고 큐에 줄 서게 하는 역할만 수행한다.

 void produce(int x)는 데이터를 써 넣는 함수이다. 이를 위해서는 빈 버퍼가 있는지 체크해야 한다. 빈 버퍼가 있으면 데이터를 넣어주면 되고 없으면 기다리게 한다. 빈 버퍼가 생길 때까지 기다린다. 이 기다리는 프로세스는 Monitor 내에서 활성화된 프로세스로 보지 않는다.

 그러면 이때 잠든 프로세스는 언제 다시 깨어나는가? 소비자가 consume을 해서 빈 버퍼가 생기면 그때 empty.signal()을 호출하여 아까 잠든 생산자 프로세스를 깨운다. 이때 잠들어 있는 생산자 프로세스가 없다면 아무 일도 일어나지 않는다.

 그리고 empty로 부터 생산자 프로세스 하나가 깨어나면 혹시나 소비자 프로세스 중에서도 데이터가 있는 버퍼가 없어서 잠들어 있는 것을 깨우기 위해 full.signal()을 수행한다. 물론 잠들어 있는 소비자 프로세스가 없다면 아무 일도 일어나지 않는다.

//----------------------------------------------------- 이거 이해 잘 안됨 -----------------------------------------------------//

Dining Philosophers Problem (Monitor)

식사하는 철학자 문제에도 Monitor를 적용하여 해결해 보자. 일단 각각의 철학자는

pickup(i); 밥 먹기 전에 젓가락을 집는데 모든 젓가락을 집을 때만 집게 하는 것이 핵심이다.

eat(); 밥을 먹는다

putdown(i); 젓가락을 내려 놓는다.

think(); 생각한다.

이 작업을 반복한다.

운영체제 7-4강 (동기화 문제 마지막 파트) image

 우선 공유 변수로 다음을 둔다.

enum { thinking, hungry, eating } state[5];로 설정한다. 젓가락을 집으려고 할 때 내 옆에 있는 철학자의 상태도 봐야하기 때문에 state를 공유 변수로 5개를 둔다.

condition self[5]; 왜 다섯 개가 있는가? 지금까지는 하나의 큐에 철학자들을 잠들게 했지만 여기선 각각의 철학자들이 각각의 큐에 잠들게 한다. 조금 특이하지만 받아들이자.

나머지 구현은 충분히 이해할 수 있을 것이다.

0개의 댓글