์์ฐ์-์๋น์ ๋ฌธ์ ๋ ์์ฐ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฐํ๋ฉด ์๋น์๋ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์๋นํ๋ ํํ์ ๋ฌธ์ ์ด๋ค. ์ปดํจํฐ ํ๊ฒฝ์์ ์๋ฅผ ๋ณด๋ฉด, ์ปดํ์ผ๋ฌ โ ์ด์ ๋ธ๋ฌ, ์น ์๋ฒ โ ์น ํด๋ผ์ด์ธํธ ๋ฑ์ด ์๋ค. ์ปดํ์ผ๋ฌ์์ ์์ฑํ ์ด์ ๋ธ๋ฆฌ์ด๋ ์ด์ ๋ธ๋ฌ์์ ์ด๋ฅผ ์๋นํ์ฌ ๊ธฐ๊ณ์ด๋ฅผ ๋ง๋ ๋ค.
์์ฐ์-์๋น์ ๊ด๊ณ๋ฅผ ๊ฐ๋จํ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ด๋ฉด ์์ ๊ฐ๋ค. ์ด ๊ด๊ณ์ ๋๋ถ๋ถ์ ์์ฐ์์์ ์์ฐํ ๋ฐ์ดํฐ ์์ ์๋น์๊ฐ ํ ๋ฒ์ ์๋นํ๋ ๊ฒฝ์ฐ๋ ๋๋ฌผ๋ค. ์์ฐํ ๋ฐ์ดํฐ๋ ์ค๊ฐ์ buffer ๋ผ๋ ์ ์ฅ ๊ณต๊ฐ(๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ)์ ์ ์ฅํด๋๊ณ ์๋น์๋ ์ฌ๊ธฐ์ ํ์ํ ๋งํผ ๊ฐ์ ธ๊ฐ๋ค. ์ฐฝ๊ณ ์ ๊ฐ๋ค.
๋ฒํผ์ ํฌ๊ธฐ๋ ํ์ค์ ์ผ๋ก ์ ํํ๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์์ฐ์๋ ๋ฒํผ ๊ณต๊ฐ์ด ๊ฐ๋ ์ฐจ๋ฉด ๋ ์ด์ ์ ์ฅํ ์ ์๋ค. ์๋น์๋ ๋ฒํผ๊ฐ ๋น์ด ์์ผ๋ฉด ๊ฐ์ ธ์ฌ ์ ์๋ค. ์ด๋ฌํ ์ ํํ ๋ฒํผ ํฌ๊ธฐ๋ฅผ bounded buffer ๋ผ๊ณ ํ๋ค.
์ ๋ฆฌ
- ์์ฐ์ ์๋น์ ๋ฌธ์
- ์์ฐ์ : ๋ฐ์ดํฐ ์์ฐ, ์๋น์ : ๋ฐ์ดํฐ ์๋น
- ์ปดํ์ผ๋ฌ โ ์ด์ ๋ธ๋ฌ, ํ์ผ ์๋ฒ โ ํด๋ผ์ด์ธํธ, ์น์๋ฒ โ ์น ํด๋ผ์ด์ธํธ
- Bounded Buffer
- Buffer๋ ์์ฐ์์ ์๋น์ ์ฌ์ด์ ์กด์ฌํ๋ ์ฐฝ๊ณ ์ ๊ฐ์
- ์์ฐ์์ ์๋น์ ์ฌ์ด์ ์๋ ์ฐจ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ํ์ํจ
- ๋ฒํผ ํฌ๊ธฐ๋ ์ ํํ๋ค.
- ์์ฐ์๋ ๊ฐ๋ ์ฐจ๋ฉด ๋ฃ์ ์ ์๋ค.
- ์๋น์๋ ๋ฒํผ๊ฐ ๋น๋ฉด ๋บ ์ ์๋ค.
1.1 Code
Main
class Test {
public static void main(String[] arg) {
Buffer b = new Buffer(100);
Producer p = new Producer(b, 10000);
Consumer c = new Consumer(b, 10000);
p.start();
c.start();
try {
p.join();
c.join();
} catch (InterruptedException e) {}
System.out.println("Number of items in the buf is " + b.count);
}
}
Buffer Class
์ด ๋ถ๋ถ์ ์ฃผ๋ชฉํด์ ๋ด์ผ ํ๋ค.
class Buffer {
int[] buf; // buf: Bounded buffer
int size; // size: ๋ฒํผ ํฌ๊ธฐ
int count; // count: ๋ฒํผ์ ์ ์ฅ๋ ๋ฐ์ดํฐ ๊ฐ์
int in; // in: ์์ฐํ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ฒํผ ์ธ๋ฑ์ค
int out; // 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; // Circular Queue
count++;
}
int remove() {
/* check if buf is empty */
while (count == 0)
;
/* buf is not empty */
int item = buf[out];
out = (out+1)%size; // Circular Queue
count--;
return item;
}
}
Buffer ํด๋์ค์ ๋ฉค๋ฒ ๋ณ์๋ฅผ ๋ณด๋ฉด
- buf: Bounded buffer
- size: ๋ฒํผ ํฌ๊ธฐ
- count: ๋ฒํผ์ ์ ์ฅ๋ ๋ฐ์ดํฐ ๊ฐ์
- in: ์์ฐํ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ฒํผ ์ธ๋ฑ์ค
- out: ์๋นํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ฒํผ ์ธ๋ฑ์ค
Producer
/****** ์์ฐ์ ******/
class Producer extends Thread {
Buffer b;
int N;
Producer(Buffer b, int N) {
this.b = b; this.N = N;
}
public void run() {
for (int i=0; i<N; i++)
b.insert(i);
}
}
Consumer
/****** ์๋น์ ******/
class Consumer extends Thread {
Buffer b;
int N;
Consumer(Buffer b, int N) {
this.b = b; this.N = N;
}
public void run() {
int item;
for (int i=0; i<N; i++)
item = b.remove();
}
}
๋ง์ฝ ์์ฑ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ์์ฑํ์ฌ ๋ฒํผ์ ๋ง์ง๋ง ์ธ๋ฑ์ค๋ก ๊ฐ๋ฉด ๊ทธ ๋ค์์ ์ฒ์์ผ๋ก ๋๋์๊ฐ๋ค. (circular buffer) ์๋นํ๋ ๊ฒ๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ค.
main์ ๋ณด๋ฉด ํฌ๊ธฐ๊ฐ 100์ธ ๋ฒํผ๋ฅผ ์์ฑํ๊ณ 2๊ฐ์ ์ฐ๋ ๋๊ฐ ๊ฐ๊ฐ ์์ฐ์์ ์๋น์ ์ญํ ์ ํ์ฌ ๊ฐ๊ฐ 10000๋ฒ์ฉ ์์ฐํ๊ณ ์๋นํ๋ค. ์ ์์ ์ธ ๊ฒฐ๊ณผ๋ count๊ฐ์ด 0์ด ์ถ๋ ฅ๋์ผ ํ๋ค.
ํ์ง๋ง ์ค์ ์ฝ๋๋ฅผ ์ํํ๋ฉด ๋ฌดํ ๋ฃจํ์ ๋น ์ง๊ฑฐ๋, count๊ฐ์ ์ ํ ์์ํ์ง ์์ ๊ฐ์ด ์ถ๋ ฅ๋๋ค.
์ด ๋ฌธ์ ๋น์ฐํ๊ฒ๋ ๋๊ธฐํ ๋ฌธ์ ์ด๋ค. ์์ฐ์์ ์๋น์๊ฐ ๋์์ ์ ๊ทผํ๋ ๊ณตํต ๋ณ์์ธ buf, count ๋ฅผ ๋ ํ๋ก์ธ์ค๊ฐ ๋์์ ์ ๋ฐ์ดํธํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ค์ ๋งํ๋ฉด ์๊ณ๊ตฌ์ญ์ ๋์์ ์ ๊ทผํ ๊ฒ์ด๋ค.
1.2 ๋๊ธฐํ ํด๊ฒฐ
ํด๊ฒฐ๋ฐฉ๋ฒ์ ์์ ๋ฐฐ์ ๋ ์ธ๋งํฌ๋ฅผ ์ฌ์ฉํ์ฌ mutual exclusion์ ๋ณด์ฅํ๋ ๊ฒ์ด๋ค. ์๊ณ๊ตฌ์ญ์ ๋์์ ์ ๊ทผํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ํ๋์ ํ๋ก์ธ์ค๋ง ํ์ฉํด์ผํ๋ค. sem
์ด๋ผ๊ณ ์ ์ธํ์ง ์๊ณ mutex
๋ผ ์ ์ธํ๋ค. ์ง๊ธ ๋ง๋๋ semaphore๋ **mut**ual **ex**clusion์ ๋ง๋ ์ญํ ์ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
Buffer Class
class Buffer {
int[] buf;
int size;
int count;
int in;
int out;
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();
buf[in] = item;
in = (in+1)%size;
count++;
mutex.release();
} catch(InterruptedException e) {}
}
int remove() {
/* check if buf is empty */
while (count == 0)
;
/* buf is not empty */
try {
mutex.acquire();
int item = buf[out];
out = (out+1)%size;
count--;
mutex.release();
return item;
} catch(InterruptedException e) {}
return -1;
}
}
์๋ ์๊ณ๊ตฌ์ญ์ ์ธ๋งํฌ๋ฅผ ์ถ๊ฐํ ์ฝ๋์ด๋ค. ์๊ณ๊ตฌ์ญ์ ์์์ ๋งํ๋ฏ์ด buf, count ์ ์ ๊ทผํ๋ ์์ญ์ด๋ฏ๋ก insert(), remove() ํจ์ ๋ด๋ถ์ ์ ์ธํ ๊ฒ์ ๋ณผ ์ ์๋ค.
1.3 Busy waiting
์ฌ๊ธฐ์ ํ ๊ฐ์ง ๋ ๋ฌธ์ ์ ์ด ์๋ค. ๋ฐ๋ก busy waiting ์ด๋ค. ์์์ busy waiting์ ์์ฐ๊ณผ ์๋นํ๊ธฐ ์ ์ ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐผ๋์ง ๋น์ด ์๋์ง ํ์ธํ๋ ๋ฌดํ ๋ฐ๋ณต๋ฌธ์ ๋งํ๋ค. ์ด๋ ์๋ฌด ์ผ๋ ํ์ง ์์ผ๋ฉด์ ๋ฌดํ์ผ๋ก ๋ฐ๋ณตํ์ฌ CPU๋ฅผ ์ ์ ํ๊ณ ์์ผ๋ฏ๋ก ๋งค์ฐ ๋นํจ์จ์ ์ด๋ค. ์ด๋ฅผ ํด๊ฒฐํ ์ ์๋ ๊ฒ๋ ์ธ๋งํฌ์ด๋ค.
class Buffer {
int[] buf;
int size;
int count;
int in;
int out;
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) {
try {
empty.acquire(); // ๋ฒํผ์ ๋น์ด์๋ ๊ณต๊ฐ์ 1 ๊ฐ์์ํจ๋ค.(๋น์ด์๋ ๊ณต๊ฐ์ด ์์ผ๋ฉด block)
mutex.acquire();
buf[in] = item;
in = (in+1)%size;
count++;
mutex.release();
full.release(); // ๋ฒํผ์ ์ฐฌ ๊ณต๊ฐ์ 1 ์ฆ๊ฐ์ํจ๋ค.
} catch(InterruptedException e) {}
}
int remove() {
try {
full.acquire(); // ๋ฒํผ์ ์ฐฌ ๊ณต๊ฐ์ 1 ๊ฐ์์ํจ๋ค.(๋ฒํผ๊ฐ ๋ชจ๋ ๋น์ด์์ผ๋ฉด block)
mutex.acquire();
int item = buf[out];
out = (out+1)%size;
count--;
mutex.release();
empty.release(); // ๋ฒํผ์ ๋น์ด์๋ ๊ณต๊ฐ์ 1 ์ฆ๊ฐ์ํจ๋ค.
return item;
} catch(InterruptedException e) {}
return -1;
}
}
busy waiting์ ์์ ๊ธฐ ์ํด ๋ ๊ฐ์ ์ธ๋งํฌ๋ฅผ ๋ ์ถ๊ฐํ์๋ค.
- empty: ๋ฒํผ์์ ๋น์ด์๋ ๊ณต๊ฐ์ ๊ฐ์(์ด๊ธฐ๊ฐ size)
- full: ๋ฒํผ์์ ์ฐจ์๋ ๊ณต๊ฐ์ ๊ฐ์(์ด๊ธฐ๊ฐ 0)
์ถ๊ฐํ ์ธ๋งํฌ ๋ณ์๋ ์์ ๊ฐ๊ณ , empty๋ ์ด๊ธฐํํ ๋ ๋ฒํผ๋ ๋ชจ๋ ๋น์ด์์ผ๋ฏ๋ก ๋ฒํผ์ ํฌ๊ธฐ๋ก ์ด๊ธฐํํ๊ณ full์ ์ด๊ธฐ ๋ฒํผ์๋ ์๋ฌด๋ฐ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฏ๋ก 0์ผ๋ก ์ด๊ธฐํํ๋ค.
๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ธฐ ์ ์ ๋น์ด์๋ ๊ณต๊ฐ์ด ์๋์ง ํ์ธํ๋ค. ์๋ค๋ฉด empty์ธ๋งํฌ์ value๊ฐ์ด -1์ด ๋๋ฏ๋ก block์ด ๋๊ณ , ์๋ค๋ฉด ์๊ณ๊ตฌ์ญ ๋ด๋ถ๋ก ์ง์ ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ค. ์์ฑ์ด ์๋ฃ๋๋ฉด full์ธ๋งํฌ์ value๊ฐ์ 1 ์ฆ๊ฐ์ํจ๋ค.(์๋น์๋ ๋ฐ๋๋ก ๋์ํ๋ค๊ณ ๋ณผ ์ ์๋ค. ์ฝ๋์ฐธ๊ณ ) ์ด ์ฝ๋๋ฅผ ์คํ์์ผ๋ณด๋ฉด ์ ์์ ์ผ๋ก ๊ฒฐ๊ณผ๊ฐ์ด 0์ด ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Reference
- KOCW ์ํฌ์ฌ ๊ต์๋ - ์ด์์ฒด์
- ์ํฌ์ฌ ๊ต์๋ ๋ธ๋ก๊ทธ(์ํ ๊ธฐ์ถ ๋ฌธ์ )
- codemcd ๋์ ์ ๋ฆฌ๊ธ
- Operating System Concepts, 9th Edition - Abraham Silberschatz