모니터 - 동시성 처리

텐저린티·2024년 1월 17일

알쓸신잡

목록 보기
10/10

모니터란?

개념

  • mutual exclusion(상호 배제) 보장
  • 조건 따라 스레드 대기 상태 전환 기능 제공

언제 사용되나?

  • 멀티스레드 환경에서 하나의 스레드만 실행해야할 때
  • 즉, 동시성 처리가 필요한 경우

구성요소 (M + CV)

class Monitor {
	Mutex m;					// 모니터 뮤텍스 (락 설정 플래그)
    ConditionVariable cv;		// 락 조건 변수 (락 설정 조건)
}

int run(Monitor moni) {
	acquire(moni.m);  			// 모니터 락 취득
    while (!p) {	 			// 조건 확인
    	wait(moni.m, moni.cv); 	// 조건 충족 안 되면 waiting Queue에 push
    }
    
    // 임계영역을 수정하는 코드 (객체 수정하는 코드)
    
    // cv2 는 cv와 같을 수도 있음
    // broadcase(moni.cv2);
    signal(moni.cv2);
    release(moni.m); 			// 모니터의 락 반환
}

Mutex

  • critical section 내 mutual exclusion 보장 위한 장치
  • critical section 진입 위해 mutext lock 필요
  • mutex lock 취득 못한 스레드는 entry queue에 들어간 후 waiting 상태로 전환
  • Mutex 락을 쥔 스레드가 락을 반환하면 락을 기다리며 큐에 대기상태로 있던 스레드 중 하나가 실행
  • Entry queue (critical section 진입 관련 큐)과 관련

Condition Variable

  • Waiting Queue 가짐
  • 조건이 충족되길 기다리는 스레드들이 대기 상태로 머무는 곳

Condition Variable 주요동작

동작설명
wait스레드가 자신을 CV 내 WaitingQ 에 넣음
signalWaitingQ 내 대기 스레드 하나 깨움
broadcastWaitingQ 내 대기 스레드 전부 깨움

두 개의 큐

종류설명
Entry QueueCritical Section 진입 대기 큐
Waiting Queue조건 충족 대기 큐

Bounded P/C problem

  • Producer 는 buffer 가 찼는지 계속 확인해야 함
  • Consumer 는 buffer 에 아이템이 있는 계속 확인해야 함
  • 모니터 활용해 해결 가능
  • CV 조건 확인 구문은 반드시 while 문 안에 배치
    - 락 획득 후 조건 확인 위해
while (q.isEmpty()) {
	wait(lock, emptyCV);
	// waiting queue 에서 나오면 여기가 PI임
}

Java 모니터

  • 모든 객체 내부적 모니터 존재
  • synchronized 키워드로 모니터 mutual exclusion 기능
  • 자바 모니터는 CV 하나만
    - 여러개가 필요한 경우 따로 설정하면 됨
  • 세 가지 동작
    - wait
    - notify
    - notifyAll (broadcast)
  • java.util.concurrent 에 동기화 클래스
class BoundedBuffer {

	private static final int SIZE = 5;
	
	private final int[] buffer = new int[SIZE];
	private int count = 0;

	// 메소드 레벨에 자바 모니터 뮤텍스 락 걸기
	// 자바 객체 내부에 있는 모니터를 사용한 것
	public synchronized void produce(int item) {
		while(count == 5) {
			wait();
		}
		buffer[count ++] = item;
		notifyAll();
	}

	public void consume() {
		int item = 0;
		// 코드 블럭에 자바 모니터 뮤텍스 락 걸기
		// 객체 인스턴스 (this)를 인자로 넘김
		synchronized (this) {
			while (count == 0) {
				wait();
			}
			item = buffer[-- count];
			notifyAll();
		}
		System.out.println("Consume: " + item);
	}
}

public class Main {
	public static void main(String[] args) throws {
		BoundedBuffer buffer = new BoundedBuffer();
		Thread consumer = new Thread(() -> buffer.consume());
		Thread producer = new Thread((item) -> buffer.produce(item));

		consumer.start();
		producer.start();

		consumer.join();
		producer.join();
	}
}
profile
개발하고 말테야

0개의 댓글