Chapter 6-2. Process Synchronization II
Bounded - Buffer Problem
버퍼의 크기가 유한한 환경에서 생산자와 소비자 사이에서 발생하는 문제를 말한다.
생산자 프로세스, 소비자 프로세스 이 두 프로세스는 하나 씩만 존재하는 것이 아니라 여러 개씩 존재한다.
생산자 프로세스의 역할은 데이터를 만들어서 공유 버퍼에 집어 넣는 역할을 하고
소비자 프로세스는 그 반대로 버퍼에 있는 데이터를 꺼내가는 역할을 하게 된다.
이로 인해 어떤 문제들이 발생할 수 있을까?
첫번째는 생산자 두 개가 하나의 버퍼에 동시에 데이터를 넣게 되는 경우이다.
하나의 프로세스가 접근을 하게 되면 공유 버퍼에 lock을 걸게 될텐데,
동시에 락을 걸게 되는 것인가? 의 문제이다.
두번째는 소비자 프로세스 두 개가 채워져있는 하나의 버퍼에 있는 데이터를 동시에 꺼내갈 때, 꺼내가려고 할 때 문제가 발생할 수 있다.
버퍼가 유한하기 때문에,
생산자 프로세스들이 공유버퍼가 Full인 상태에서 생산자 프로세스가 또 도착하게 되면
새로 도착한 생산자 프로세스는 사용할 수 있는 자원이 없다.
생산자 입장에서의 자원은 데이터를 넣을 수 있는 버퍼를 의미하기 때문이다.
그렇기 때문에 소비자 프로세스가 나타나서 공유 버퍼의 공간을 비워줄 때까지 데이터를 넣지 못한다.
생산자 입장에서는 비어있는 버퍼가 카운팅해야 할 자원이다.
반대로
소비자 프로세스들이 이미 버퍼에 있던 데이터들을 모두 꺼내간 상태에서, 또 소비자 프로세스가 도착하게 되면
꺼내갈 데이터가 없기 때문에, 소비자 프로세스가 사용할 수 있는 자원이 없게 된다.
역시 새로 도착한 소비자 프로세스는 생산자 프로세스가 와서 데이터를 넣어주기 전까지 대기해야 한다.
위의 문제들을 미루어 볼 때,
생산자 프로세스가 자신의 일을 수행하기 위해 점검할 사항들에는 어떠한 것들이 있을까
Empty 버퍼가 존재하는지 확인
공유데이터에 lock을 거는 기능
Empty 버퍼에 데이터를 입력하는 기능
unlock의 기능
그리고 full buffer의 개수를 하나 증가시켜 counting하는 기능
이런 기능이 필요할 것이다.
마찬가지로 소비자 프로세스도 비슷한 기능들을 수행해야 한다.
Full buffer가 존재하는지 확인
공유데이터에 lock을 거는 기능
Full 버퍼에 데이터를 출력하는 기능
unlock의 기능
그리고 Emptry buffer의 개수를 하나 증가시켜 counting하는 기능
이런 기능이 필요할 것이다.
do{ produce an item in x P(empty); P(mutex); add x to buffer V(mutex); V(full); } while(1);
Consumer Process pseudocode>
do{ P(full); P(mutex); remove a item from buffer to y V(mutex); V(empty); consume an item in y } while(1);
Semaphores의 한계를 극복하기 위해서 등장한,
Monitor
동시 수행중인 프로세스 사이에서 abstract data type의 안전한 공유를 보장하기 위한 것이다.
high-level synchronization construct이며
공유 데이터와 공유데이터에 접근할 수 있는 프로시저를 하나의 모니터에 함께 묶어두는 방법이다.
Monitor 방식을 이용하면 lock을 걸 필요도, unlock을 해줄 필요도 없게 된다.
모니터 자체에 동시 접근할 수가 없게 되는 것이다.
모니터 내에서는 한번에 하나의 프로세스만이 활동 가능하다.
프로그래머가 동기화 제약조건을 명시적으로 코딩할 필요가 없어지게 되는 것이다.
프로세스가 모니터 안에서 대기할 수 있게 하기 위해
condition variable 를 사용하여 이를 제어해준다.
wait의 방식과 signals의 방식을 사용해서 말이다.
위의 생산자-소비자 문제를 Monitor를 사용하여 pseudocode를 작성하면 다음과 같다.
monitor bounded_buffer { int buffer[N]; condition full, empty; void produce(int x) { if there is no empty buffer empty.wait(); and x to an empty buffer full.signal(); } void consume(int * x) { if there is no full buffer full.wait(); remove an item from buffer and store it to &x empty.signal() } }
프로그래머 입장에서 가독성이 훨씬 더 좋아진 것이다.
가독성 뿐만 아니라, 작업을 수행하는데 있어서도 훨씬 좋아졌다.
Chapter 6-2. 끝
이 포스팅은 이화여대 반효경 교수님 강의를 듣고 요약한 내용을 담고 있습니다.
'Dev.Basic > 운영체제' 카테고리의 다른 글
[OS] 8-1. Memory Management I (0) | 2016.06.05 |
---|---|
[OS] 7. Deadlock (0) | 2016.06.04 |
[OS] 6-1. Process Synchronization I (0) | 2016.06.03 |
[OS] 5-2. CPU Scheduling II (0) | 2016.06.02 |
[OS] 5-1. CPU Scheduling I (0) | 2016.05.31 |