본문 바로가기

ComputerScience/Operating System

OS - 5.2 Concurrency: Mutual Exclusion and Synchronization

728x90

8. Monitors

- 이제까지 mutual exclusion을 구현하기 위한 하드웨어의 지원 방법과 os의 지원방법을 공부했다.

- 세마포어를 활용한 상호배제는 올바르게 구현하기가 어렵다. 그래서 생겨난 더 쉬운 방법이 모니터이다.

- 세마포어를 프로그램으로 구현한게 모니터이다.

- 이번에는 Programming Language차원에서, 좀더 high level로 비교적 쉽게 mutual exclusion을 지원하는 방법을 알아본다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- 모니터라는 공간은 공유자원과 공유자원에 대한 접근 함수가 있는 공간이다. 이 공간에는 프로세스가 하나만 존재할 수 있다.

- 또한 공유 자원에 대한 접근은 모니터 내부에 있는 접근 함수를 통해서만 가능하다.

- 이 한명만 존재할 수 있다는 규칙으로 상호배제가 보장되는 것이다.

- 그림에서 entrance를 통해 한명(process, thread)씩 모니터 공간으로 들어가게 된다.

 

- 모니터에 들어온 프로세스(a)는 자기가 필요한 자원(x)에 접근한다.

- 이어서 프로세스(b)가 모니터에 들어가서 자원(x)을 얻으려 하면 cwait으로 b는 해당하는 조건에 따라 block되어 queue로 이동한다.

- 현재 모니터에는 a만 있고 b는 block되어있다.

 

- 그러다 a가 일을 마치고 csignal을 통해 x의 사용 완료를 알려주면 잠자고 있던 b가 깨어나는 것이다.

- 이때 a는 모니터 밖으로 나가기고 b가 모니터 안에 혼자 있게 된다.

 

- 이번에는 a가 x,y의 자원을 요구했다고 하자.

- a는 x,y를 점유하고 일을 한다.

- 이때 b가 모니터에 접근해서 x를 달라고 요청한다.

- 그럼 모니터는 "x는 사용불가"하다는 조건으로 b를 block시킨다.

- a가 x를 다 써서 csignal(x)를 날리면 잠자고 있던 b가 깨어난다.

- 그런데 이 상황에서는 모니터에 a와 b가 공존하게 된다.

- 따라서 고안한 해결책이 a를 urgent queue로 이동시키는 것이다.

- csignal을 날렸지만 아직 할일이 좀 남은 프로세스는 urgent queue로 이동하여 b가 모니터를 비워줄 때까지 잠시 a는 block된 채로 urgent queue에 있게 되는 것이다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- 생산자 소비자 문제를 모니터로 해결해보자.

- producer, consumer함수를 보면 매우 간단하다. 생상자는 데이터를 만들고 버퍼에 넣고 소비자는 데이터를 버퍼에서 꺼내고 소비한다.

- apend(), take()라는 함수가 각각 모니터에 해당한다.

 

- take()를 살펴보자.

- count == 0이어서 버퍼가 비어있음을 확인하면 cwait(notempty)를 호출해서 "버퍼가 비어있지 않다"는 조건이 만족될때까지 queue에서 대기하게 된다.

- notempty조건이 만족되면 condition queue를 나와서 procedure를 수행할 수 있게 된다.

- 끝으로 csignal(notful)을 호출해서 현재 버퍼가 notful이라는 조건변수를 바꿈으로써 신호를 보내 block된 생산자를 깨운다.

 

- apend()를 살펴보자.

- count==N으로 버퍼가 곽차면 cwait(notful)로 "버퍼가 꽉차있지 않다"는 조건이 만족될때까지 queue에서 대기한다.

- notful 조건이 만족되면 condition queue를 나와서 procedure를 진행한다.

- 끝으로 csignal(notempty)를 호출해서 현재 버퍼가 notempty라는 조건변수를 바꿈으로써 신호를 보내 block된 소비자를 깨운다.

9. Message Passing

- 이번에는 상호배제와 동기화 문제를 프로세스가 서로 통신을 하는 관계로 생각해보자.

- 이때 프로세스간의 상호배제와 더불어 communication과 synchronization을 어떻게 구현할 것인가?

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- s1~sn은 r1이라는 자원에 대한 점유를 원한다.

- 각각의 프로세스들은 R1이 사용가능하다는 메시지가 올 때를 기다리고 있다.

- 메세지가 오면 메세지를 한 프로세스가 먼저 receive하고 자원을 점유한다. 

- 자원을 다 사용하고 나면 "R1을 사용해도 돼"라는 메세지를 다시 send한다.

- 그럼 이어서 메세지를 먼저 받은 다른 프로세스가 receive를 하여 자원을 점유하게 되는 것이다.

 

- 이처럼 Message Passing은 send(), receive() 두 함수를 제공하여 이 문제를 해결한다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- p1부터 pn까지 프로세스들이 동시에 실행되었고 각 프로세스는 receive를 통해 메세지를 받아서 critical section으로 진입한 후 작업이 끝나면 send()를 통해 메세지를 보내면서 마무리 된다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- 앞에서 살펴본 생산자 소비자 문제를 message passing으로 해결해보자.

- 일단은 main함수에서 생산 가능하다는 메세지를 넣을 수 있는 우체통을 만든다.

- 마찬가지로 소비할 수 있다는 메세지를 넣을 수 있는 우체통을 만든다.

 

- 생산자는 receive(mayproduce)로 우체통을 확인하여 "생산을 할 수 있다"는 메세지를 받는다. 만약 메세지가 우체통에 없다면(메세지를 아직 못 받았다면) block된 채로 메세지 수신을 기다리고 있을 것이다.

- 그렇게 메세지를 받으면 일을하고 소비자를 위해 "소비가 가능하다"는 내용의 메세지를 우체통에 넣어둔다 : send(mayconsume).

 

- 소비자는 우체통을 확인하여 mayconsume의 메세지가 도착했는지 확인하고 있다면 receive하여 데이터를 소모하고

- 일을 다 마쳤다면 send(mayproduce)를 통해 생산자를 위해 "생산이 가능하다"라는 내용의 메세지를 우체통에 넣어둔다.

*blocking, non-blocking

- blocking send, blocking receive : 수신자와 송신자는 자신들의 요청에 대한 응답이 올때까지 아무것도 안하고 기다린다. 이를 랑데부(rendezvous)라고 한다.

- nonblocking send, blocking receive : 송신자는 자신의 요청에 대한 대답이 오지 않더라도 계속 이어서 작업을 수행하지만 수신자는 응답이 올때까지 아무것도 하지 않는다.

- nonblocking send, nonblocking receive : 송신자, 수신자 모두 자신들에 대한 요청의 대답을 기다리지 않고 계속 각자 작업을 수행한다.

10. Reader Writers Problem

- 이번에는 하나의 메모리 공간을 여러 reader와 writer가 사용을 원하는 상황으로 빗대어 상호배제, 동기화 문제를 해결해 보자.

- 한권의 책(메모리 공간)을 여러명이 함께 보는 일은 가능하다.

- 하지만 여러명의 작가가 동시에 한 공간(메모리 공간)에 글을 쓰는 것은 불가능하다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- 메세지 패싱으로 독자와 작가의 문제를 해결해보자

- 독자는 메모리 공간을 읽고 싶다는 메세지를 보낸다. send(readrequest,rmsg)

- receive(mbox[i],rmsg)를 통해 읽기가 가능하다는 메세지를 받고

- 작업을 마친 후 send(finished,rmsg)를 통해 읽기를 끝냈다는 메세지를 보낸다.

 

- 작가는 send(writerequest,rmsg)를 통해 쓰기를 하고 싶다는 메세지를 보낸다.

- receive를 통해 쓰기가 가능하다는 메세지를 받으면

- 작업을 수행하고 send(finished,rmsg)를 통해 쓰기를 마쳐다는 메세지를 보낸다.

 

- controller가 request에 대한 메세지들을 받아서 독자와 작가에게 각각의 id(이름)을 확인하여 "OK"라는 승인 메세지를 보내준다. 독자와 작가는 cotroller로 부터의 message를 수신하는 것이다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- 이 구현에서는 세마포어를 활용했다.

- writer는 semWait(wsem)으로 다른 writer가 메모리를 쓰고 있는지 확인한다. 

- writer가 이미 있다면 semWait에서 block될 것이고 반대라면 critical section으로 진입한다.

- 쓰기를 완료하면 semSignal(wsem)을 통해 다시 쓰기가 가능해졌으니 잠자고 있던, block되어있던 작가를 깨우는 신호를 보낸다.

 

- 동시에 여러 reader가 데이터를 읽을 수 있다고 했다.

- 첫번째 semWait(x), semSignal(x)쌍은 reader를 추가하는 critical section을 보호한다.

- 내가 첫 reader 라면 readcount가 1일 것이고 그럼 writer가 있을 수도 있으니 semWait(wsem)으로 writer가 메모리를 쓰고있는지 확인한다. 

- 만약 reader가 1이라면 semWait에서 writer는 block되고 반대의 경우 reader는 critical section으로 들어간다.

- 내가 첫 reader가 아니라면 readcount가 1이 아닐 것이고 그럼 writer가 없다는 것이 보장되었기 때문에 if문을 넘어간다.

- 그럼 reader가 한명 추가된다.

 

- 마지막으로 뒷부분의 semWait(x)와 semSignal(x)쌍은 reader를 한명 줄여주는 critical section을 보호한다.

- 만약 reader가 0명이라면 semSignal(wsem)으로 잠자고있던 writer를 깨운다.

- 0이 아니라면 reader한명이 읽기를 마쳤으므로 readcount를 하나 줄여준다.

 

- 이 코드에서는 한명의 reader가 일단 자원에 접근하면 나머지는 semWait(wsem)를 호출하지 않는다. 즉 일단 제어권을 가지면 reader가 계속해서 추가될 수 있는 것이다.

- 즉 reader가 writer보다 우선하는 상황이다.

https://www.unf.edu/public/cop4610/ree/Notes/PPT/PPT8E/

- 이번에는 reader가 writer보다 우선하는 상황을 구현해보자.

- writer()를 먼저 살펴보자

- semWait-semSignal이 세쌍이 보인다. 즉 세 critical section을 한명만 사용하도록 보장하고 있다는 뜻이다.

- 일단 첫번째 영역은 writer가 한명 추가 되었음을 표시하고 만약 writer가 1명이라면 semWait(rsem)로 reader를 block시킨다.

- 두번째 영역은 semWait(wsem)으로 write가 가능한지 확인하고 쓰기를 마치면 semSignal(wsem)으로 다른 작가를 깨운다.

- 마지막 영역은 writer를 감소시키고 만약 writer가 없다면 semSignal(rsem)으로 잠자고 있던 reader를 깨운다.

 

- reader()를 보자

- z, rsem, x 세 세마포어를 얻어야만 reader가 증가된다.

- 만약 내가 첫 reader라면 semWait(rsem)으로 writer를 block시킨다.

- 그게 아니라면 계속해서 readercount가 증가될 수 있다.

- read를 마치면 

- 마지막 영역에서 readcount를 줄여주고 마지막 reader였다면 semSignal(wsem)로 잠자던 reader를 깨운다.

 

- 이 상황에서는 writer가 한번 주도권을 잡으면 writer가 전부 빠져나가고 나서야 reader가 자원을 잡을 수 있다.

- 즉 write를 우선적으로 다 받아들이고 나서 reader에게 자원을 할당한다.

728x90
반응형