KOCW에서 제공하는 경성대학교 양희재 교수 운영체제 강의를 듣고 정리한 글 입니다.
1. 모니터
1) 모니터란?
- 세마포 이후 프로세스 동기화 도구이다. 세마포 보다 고수준 개념이다.
- 세마포어보다는 구조가 복잡하지만, 사용하기는 더 편리하다.
2) 모니터 구조
모니터는 공유 자원과 공유 자원 접근 메소드로 이루어져 있다.
모니터에는 배타 동기를 위한 큐와 조건 동기를 위한 큐 2개가 있다.
공유 자원 접근 메소드는 최대 1개 메소드만 접근할 수 있다.
나머지 메소드는 배타 동기를 위한 큐에서 기다리고있는다.
진입했던 쓰레드는 wait() 콜에 의해 조건 동기를 위한 큐로 들어가게되고(block), 새로운 쓰레드는 진입 가능하다.
새 쓰레드는 notify()로 조건 동기 큐에 block되었던 쓰레드를 깨울 수 있다
깨워진 쓰레드는 현재 쓰레드가 나가면 재진입할 수 있다.
2. 자바 모니터
자바의 모든 객체는 모니터가 될 수 있다.
- 배타동기: synchronized 키워드 사용하여 지정
- 조건동기: wait(), notify(), notifyAll() 메소드 사용
하나의 쓰레드만 공유자원 접근함수에 접근할 수 있다.
즉, 한 쓰레드가 f() 메소드를 쓰고있다면, 다른 쓰레드는 f() 또는 g()에 접근할 수 없다.
1) 모니터 사용
(1) 사용 방법
synchronized {
/* Critical-Section */
}
모니터를 이용해 한번에 하나의 쓰레드만 공유자원을 이용하게 만들 수 있다. 단지 synchronized를 메소드 앞에 붙이면 된다.
synchronized 메소드를 사용하여 공통 변수를 업데이트 하는 메소드를 모니터라 한다.
(2) 사용 예시 1 : 상호 배제 Mutual Exclusion
은행 계좌 문제
/* Monitor : Mutual Exclusion
Bank Account Problem */
class BankAccount {
int balance;
synchronized void deposit(int amt) {
int temp = balance + amt;
System.out.print("+");
balance = temp;
}
synchronized void withdraw(int amt) {
int temp = balance - amt;
System.out.print("-");
balance = temp;
}
int getBalance() {
return balance;
}
}
/*
Output
+++++++++++++++++++++++++++--------------------------------------++++++++++------------------+++++++++++++++++++++++-----------+++++++++++++++++++++++++-------------------------+++++++++++++++--------
balance = 0
*/
잔액 0으로 정상적으로 출력된다.
(2) 사용 예시 2 : 순서 정하기 Ordering
모니터를 이용해 어느 메소드를 먼저 실행할지 설정할 수 있다.
P1 | P2 |
wait(); | |
S1; | S2; |
notify(); |
은행 계좌 문제에서는 아래처럼 하면 된다.
① 입금 먼저
위의 표에서 S1은 deposit, S2는 withdraw가 된다.
/* Monitor : Ordering
Bank Account Problem */
class BankAccount {
int balance;
synchronized void deposit(int amt) {
int temp = balance + amt;
System.out.print("+");
balance = temp;
notify();
}
synchronized void withdraw(int amt) {
while (balance <= 0)
try {
wait();
} catch (InterruptedException e) {}
int temp = balance - amt;
System.out.print("-");
balance = temp;
}
int getBalance() {
return balance;
}
}
/*
Output
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------+++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------
Balance = 0
*/
② 출금 먼저
notify(), wait()을 deposit, withdraw에 바꿔주면되는데 부등호 바꿔줘야한다.
③입출금 번갈아가면서
/* Monitor : Ordering
Bank Account Problem */
class BankAccount {
int balance;
/* p_turn : Parent Turn */
boolean p_turn = true;
synchronized void deposit(int amt) {
int temp = balance + amt;
System.out.print("+");
balance = temp;
/* child 깨우고 자신 block */
notify();
p_turn = false;
try {
wait();
} catch (InterruptedException e) {}
}
synchronized void withdraw(int amt) {
/* 처음에는 wait() */
while (p_turn)
try {
wait();
} catch (InterruptedException e) {}
int temp = balance - amt;
System.out.print("-");
balance = temp;
/* child 종료 후 notify()로 부모 깨우고, p_turn 바꾸기 */
notify();
p_turn = true;
}
int getBalance() {
return balance;
}
}
/*
Output
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
최초에 p_turn이 true여서 입금 먼저 실행하게 된다.
(3) 사용 예시 3 : 생산자-소비자 문제 Bounded Buffer Problem
/* Monitor : Bounded Buffer Problem */
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;
}
synchronized void insert(int item) {
while (count == size)
try {
wait();
} catch (InterruptedException e) {}
buf[ in ] = item; in = ( in +1) % size;
notify();
count++;
}
synchronized int remove() {
while (count == 0)
try {
wait();
} catch (InterruptedException e) {}
int item = buf[out];
out = (out + 1) % size;
count--;
notify();
return item;
}
}
/*
Output
Number of items in the buf is 0
*/
(4) 사용 예시 : 식사하는 철학자 문제 Dining Philosopher Problem
Semaphore 대신 모니터를 사용해 Chopstick 으로 대체하였다.
/* Monitor : Dining Philosopher Problem */
class Philosopher extends Thread {
int id; // philosopher id
Chopstick lstick, rstick; // left, right chopsticks
Philosopher(int id, Chopstick lstick, Chopstick rstick) {
this.id = id;
this.lstick = lstick;
this.rstick = rstick;
}
public void run() {
try {
while (true) {
lstick.acquire();
rstick.acquire();
eating();
lstick.release();
rstick.release();
thinking();
}
} catch (InterruptedException e) {}
}
void eating() {
System.out.println("[" + id + "] eating");
}
void thinking() {
System.out.println("[" + id + "] thinking");
}
}
class Chopstick {
private boolean inUse = false;
synchronized void acquire() throws InterruptedException {
while (inUse)
wait();
inUse = true;
}
synchronized void release() {
inUse = false;
notify();
}
}
class Main {
static final int num = 5; // number of philosphers & chopsticks
public static void main(String[] args) {
int i;
/* chopsticks */
Chopstick[] stick = new Chopstick[num];
for (i = 0; i < num; i++)
stick[i] = new Chopstick();
/* philosophers */
Philosopher[] phil = new Philosopher[num];
for (i = 0; i < num; i++)
phil[i] = new Philosopher(i, stick[i], stick[(i + 1) % num]);
/* let philosophers eat and think */
for (i = 0; i < num; i++)
phil[i].start();
}
}
'CS > OS' 카테고리의 다른 글
[운영체제] 8. 프로그램을 메인 메모리에 올리기 (MMU) (0) | 2024.12.13 |
---|---|
[운영체제] 8. 주기억장치 관리 개요 (0) | 2024.12.11 |
[운영체제] 7. 교착상태 Deadlock (0) | 2024.12.11 |
[운영체제] 동기화 예제 3) 식사하는 철학자 문제 (0) | 2024.12.11 |
[운영체제] 동기화 예제 2) 공유 데이터베이스 접근 문제 (0) | 2024.12.11 |