반응형
1. 생산자-소비자 문제 Bounded Buffer Problem
1) 생산자-소비자 문제
- 생산자 프로세스가 데이터를 생산하면 소비자 프로세스는 그것을 소비한다.
- -> 버퍼는 생산자와 소비자가 모두 접근하는 임계 구역인 셈이다.
- -> 세마포어를 사용해서 상호 배제로 문제를 해결할 수 있다.
- 예) 컴파일러(생산) > 어셈블러(소비), 파일 서버(생산) > 클라이언트(소비), 웹 서버(생산) > 웹 클라이언트(서버)
(1) Bounded Buffer
- 생산된 데이터는 버퍼에 저장한다.(속도 차이 등 때문에)
- 현실 시스템에서 버퍼 크기는 유한하다. (bounded : 한계가 있는)
- 생산자는 버퍼가 가득 차면 더 넣을 수 없다.
- 소비자는 버퍼가 비면 뺄 수 없다.
2) 예제 코드
Producer는 버퍼에 10,000개 아이템을 넣고, Cosumer는 버퍼에서 10,000 개 아이템을 찾는다.
프로그램이 종료된 후 아이템은 0개가 남아있어야한다.
count : buf에 생산된 데이터의 갯수
size : buf의 크기
in : buf에 데이터가 in되는 위치(index)
out : buf에 데이터가 out되는 위치(index)
(이렇게 동작하면 circural하게 동작한다.)
class Buffer {
int[] buf;
int size;
int count;
int in;
int out;
Buffer(int size) {
buf = new int[size];
this.size = size;
count = in = out = 0;
}
void insert(int item) {
/* check if buf is full */
while(count == size) { }
/* buf is not full */
buf[in] = item;
in = (in + 1) % size;
count++;
}
int remove() {
/* check if buf is empty */
while (count == 0) { }
/* buf is not empty */
int item = buf[out];
out = (out + 1) % size;
count--;
return item;
}
}
class Producer extends Thread {
Buffer buf;
int sz;
Producer(Buffer buf, int sz) {
this.buf = buf;
this.sz = sz;
}
@Override
public void run() {
for(int i = 0; i < sz; i++) {
buf.insert(i);
}
}
}
class Consumer extends Thread {
Buffer buf;
int sz;
Consumer(Buffer buf, int sz) {
this.buf = buf;
this.sz = sz;
}
@Override
public void run() {
int item = 0;
for(int i = 0; i < sz; i++) {
item = buf.remove();
}
}
}
class Main {
public static void main(String[] args) {
Buffer buf = new Buffer(100);
Producer p = new Producer(buf, 10000);
Consumer c = new Consumer(buf, 10000);
p.start();
c.start();
try {
p.join();
c.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("Number of items in the buf is " + buf.count);
}
}
/*
Output
Number of items in the buf is 25
*/
문제점
위의 코드는 동작 안하거나 잘못된 결과나온다. (버퍼 안 아이템 수 25가 나왔다)
원인은 공통변수 업데이트 구간(= 임계구역)에 대한 동시 진입했기 때문이다. (공통변수 count, buf[] 동시에 업데이트)
해결 방법은 세마포어를 사용해 임계구역에 대한 동시 접근 방지 (상호배타)
수정 코드
import java.util.concurrent.Semaphore;
class Buffer {
int[] buf;
int size;
int count;
int in;
int out;
/* mutex : mutual exclusion */
Semaphore mutex;
Buffer(int size) {
buf = new int[size];
this.size = size;
count = in = out = 0;
mutex = new Semaphore(1);
}
void insert(int item) {
/* check if buf is full */
while(count == size) { }
/* buf is not full */
try {
mutex.acquire();
//////////// Critical Section /////////////////
buf[in] = item;
in = (in+1)%size;
count++;
///////////////////////////////////////////////
mutex.release();
} catch (InterruptedException ex) {}
}
int remove() {
/* check if buf is empty */
while (count == 0) { }
/* buf is not empty */
try {
mutex.acquire();
//////////// Critical Section /////////////////
int item = buf[out];
out = (out + 1) % size;
count--;
mutex.release();
return item;
///////////////////////////////////////////////
} catch (InterruptedException ex) {}
return -1;
}
}
/*
Output
Number of items in the buf is 0
*/
여러번 실행 해도 0으로 맞게 나온다.
세마포어를 사용해 임계구역 문제를 해결했다.
2) Busy Wait
(1) Busy Wait 이란?
- 생산자는 버퍼가 가득 찬 경우 빈공간이 있는지, 소비자는 버퍼가 빈 경우 데이터가 있는지 계속 확인해야해서 CPU 낭비를 초래한다.
- -> 쉬는데 바쁘다는 의미로 Busy Wait 이라고한다.
- 이를 해결하기 위해 세마포어 2개를 추가해 해결한다.
(2) 세마포어를 사용한 busy-wait 회피
세마포어 full, empty를 추가한다.
full의 permit은 0, empty의 permit 은 BUF_SIZE
import java.util.concurrent.Semaphore;
class Buffer {
int[] buf;
int size;
int count;
int in;
int out;
/* mutex : mutual exclusion */
Semaphore mutex, full, empty;
Buffer(int size) {
buf = new int[size];
this.size = size;
count = in = out = 0;
mutex = new Semaphore(1);
full = new Semaphore(0);
empty = new Semaphore(size);
}
void insert(int item) {
/* buf is not full */
try {
empty.acquire();
mutex.acquire();
//////////// Critical Section /////////////////
buf[in] = item;
in = (in+1)%size;
count++;
///////////////////////////////////////////////
mutex.release();
full.release();
} catch (InterruptedException ex) {}
}
int remove() {
/* buf is not empty */
try {
full.acquire();
mutex.acquire();
//////////// Critical Section /////////////////
int item = buf[out];
out = (out + 1) % size;
count--;
mutex.release();
empty.release();
return item;
///////////////////////////////////////////////
} catch (InterruptedException ex) {}
return -1;
}
}
/*
Output
Number of items in the buf is 0
*/
생산자 | 소비자 |
empty.acquire(); PRODUCE; full.release(); |
full.acquire(); CONSUME; empty.release(); |
세마포어를 사용해 임계구역 문제를 해결했고,
세마포어 2개를 추가해 busy wait 문제를 해결했다.
728x90
반응형
'CS > OS' 카테고리의 다른 글
[운영체제] 동기화 예제 3) 식사하는 철학자 문제 (0) | 2024.12.11 |
---|---|
[운영체제] 동기화 예제 2) 공유 데이터베이스 접근 문제 (0) | 2024.12.11 |
[운영체제] 은행 계좌 문제 (세마포어) (0) | 2024.12.11 |
[운영제제] 3-7주차. 프로세스 관리(스케줄링, 동기화) (0) | 2024.12.10 |
[운영체제] 2. 운영체제의 개요, 역사, 현대의 운영체제 (0) | 2024.12.10 |