본문 바로가기
자바/개념

[java/개념] 세마포어(Semaphore)와 뮤텍스(Mutex)

by drCode 2021. 11. 6.
728x90
반응형
728x90

참고 자료 

1) 우테코 : https://www.youtube.com/watch?v=oazGbhBCOfU 

2) 세마포어 자바소스 : https://blog.naver.com/vanillasea81/220405264484

 

반응형

 

이번 포스팅은 세마포어(Semaphore)와 뮤텍스(Mutex)에 대해 알아보겠습니다.

 

먼저 세마포어와 뮤텍스에 대해 알아보기 전, 몇가지 알아봐야할 것이 있습니다.

 

1. 교착 상태

  • 두 가지 이상의 작업이 서로 상대방의 작업이 끝나기를 하염없이 기다리는 상태를 말한다.
  • 서로 사용할 수 있는 공유된 리소스(종이, 연필) 등을 공유 자원 혹은 임계 영역이라 한다.

 

교착상태 예시

 

 

2. 임계 영역

  • 임계 영역은 작업들이 리소스를 같이 사용할 수 있는 공유 자원이 있는 곳이므로 한 작업이 자원을 점유하면, 다른 자원은 리소스를 점유한 작업이 종료될 때까지 기다려야 한다.

임계 영역에서 선점한 자원이 독점적인 리소스 점유를 갖는다

 

3. 교착상태가 발생할 수 있는 4가지 조건

  • 상호 배제(Mutual exclusion)
  • 점유 대기
  • 비선점
  • 순환 대기

 

4. 상호 배제

  • 상호 배제란 프로세스들이 필요로 하는 자원에 대해 배타적인 통제권을 요구하는 것
  • 하나의 프로세스가 공유 자원을 사용할 때 다른 프로세스가 공유 자원에 접근하는 것을 통제하는 것

 

5. Mutex

  • 여러 스레드를 실행하는 환경에서 자원에 대한 접근 제한을 강제하기 위한 동기화 매커니즘

 

Example) 화장실에 있는 유일한 변기칸(공유된 자원)

  1. 대변이 마려운 한명이 변기칸에 들어감
  2. 들어간 사람은 이제 변기칸에 다른 사람이 들어오지 못하도록 문을 걸어 잠굼(Lock)
  3. 대변이 마려운 새로운 사람이 화장실 도착, 유일한 변기칸에 진입을 시도
  4. 기존에 들어간 사람이 나올 때까지 기다려야 함
  5. 기존에 들어간 사람이 나올 때까지 기다리는 사람이 더 증가

Mutex는 대기큐를 생성해두고, 임계 영역에 스레드가 있을 경우 다른 스레드가 공유 자원을 사용하려고 한다면 스레드를 Blocking하고 대기큐에 Sleep 시킨다.

 

6. Spin Lock

  • 화장실 변기칸에 Lock이 걸린 상태에서 언제 다 변을 보는지 물어보는 방법
  • 대기하는 사람이 언제 끝나냐고 계속 물어보는 방식
  • Busy Wating -> 점유한 프로세스가 대응하느라 다른 업무로 진행이 불가.

 

7. Spin Lock을 사용하면 좋을 때

  • Context Switching이 짧을 때(문맥교환이 짧을 때)
  • 멀티코어 프로세스일 때

 

8. 세마포어(Semaphore)

  • 멀티 프로그래밍 환경에서 다수의 프로세스나 스레드의 여러개의 공유 자원에 대한 접근을 제한하는 방법으로 사용되는 동기화 기법
  • 뮤텍스랑은 다르게, 여러 프로세스가 접근이 가능하다.

Example) 화장실 변기칸 여러 개

  1. 최대 3명까지 수용 가능, 다 점유시 0으로 표시
  2. 변기칸에 진입하는 사람은 P, 변기칸에서 나가는 사람은 V
  3. P = 기다리는 시간, V = 볼일 다 본 사람
  4. 대기자가 변기에 진입하면 또 다른 변기 대기자가 왔을 때 
    Sleep Wating -> 빈 자리 있을 시 Sleep 된 Thread를 깨움
    Busy Wating  -> 사용 가능한 자리가 생길 때까지 계속 물어보며 기다림
  5. 남은 자리가 음수이면 음수의 수 만큼 사람이 기다리는 중

 

※ 개념 정리

1) Mutex

  • 여러 Thread를 사용하는 환경에서 자원에 대한 접근을 강제하기 위한 동기화 매커니즘이다.
  • Boolean 타입의 Lock 변수를 사용한다.
  • 공유 자원을 사용 중인 Thread가 있을 때, 다른 Thread가 공유 자원에 접근한다면 Blocking 후 대기 큐로 보낸다.
  • Lock을 걸은 Thread만 Lock을 해제할 수 있다.

2) Spin Lock

  • 기본적으로 Mutex와 유사함
  • Busy-wating을 하며, 대기 큐를 갖지 않는다.
  • Mutex-Non Blocking 모델로 볼 수 있다.

3) Semaphore

  • 세마포어 변수를 통해 wait, signal을 관리한다. 세마포어 변수는 0 이상의 정수형 변수를 갖는다.
  • 계수 세마포어로 사용할 수 있으며, 접근 가능한 공유 자원의 수가 1개일 때는 이진 세마포어로 Mutex처럼 사용할 수 있다.
  • Lock을 걸지 않은 Thread도 Signal을 보내 Lock을 해제할 수 있다.

 

Mutex 자바 예제

 

Account.java

package mutex;

public class Account {
	int balance = 1000;
	// 정수를 매개변수로 받아서
	// balance의 값보다 작거나 같으면
	// balance에서 빼주는 메소드
	// 돈을 찾는 메소드
	public void withdraw(int money) {
		if(balance >= money) {
			try {
				Thread.sleep(1000);
			} catch (Exception e) {}
			
			balance -= money;
		}
	}
}

 

Bank.java

package mutex;

// Thread로 사용할 클래스
public class Bank extends Thread{
	// 여러 개의 객체가 공유해서 사용할 수 있는 변수 
	static Account obj = new Account();
	
	// 문자열을 매개변수로 받아서 스레드의 이름으로
	// 사용할 생성자
	public Bank(String name) {
		super(name);
	}
	
	// 스레드로 수행할 메소드
	public void run() {
		while(true) {
			synchronized(obj) {
				// 100 ~ 300을 랜덤하게 추출
				int money = (int)(Math.random() * 1 + 3) * 100;
				if(obj.balance >= money) {
					System.out.println(getName() + "의 balance : " + obj.balance);
					System.out.println(getName() + "의 찾는 금액 : " + money);
					obj.withdraw(money);
					System.out.println(getName() + "의 balance : " + obj.balance);
				} else {
					break;
				}
			}
		}
	}
}

 

MutexTest.java

package mutex;

public class MutexTest {
	public static void main(String[] args) {
		Bank th1 = new Bank("ATM");
		Bank th2 = new Bank("은행");
		
		th1.start();
		th2.start();
	}
}

 

Semaphore 자바 예제

SyncMulti.java

package semaphore;

import java.util.concurrent.Semaphore;

public class SyncMulti extends Thread{
	Semaphore sem;
	String msg;
	public SyncMulti(Semaphore sem, String msg) {
		super();
		this.sem = sem;
		this.msg = msg;
	}
	
	public void run() {
		try {
			sem.acquire();	// 실행한다.
			System.out.println(msg);
			Thread.sleep(5000);	// 5초간 딜레이
			sem.release();	// 끊어준다.
			// 세마포어를 실행시키고 5초 후에는 세마포어를 끊어준다.
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

 

SemaphoreTest.java

package semaphore;

import java.util.concurrent.Semaphore;

public class SemaphoreTest {
	public static void main(String[] args) {
		Semaphore se = new Semaphore(3);
		SyncMulti th1 = new SyncMulti(se, "1");
		SyncMulti th2 = new SyncMulti(se, "2");
		SyncMulti th3 = new SyncMulti(se, "3");
		SyncMulti th4 = new SyncMulti(se, "4");
		
		th1.start();
		th2.start();
		th3.start();
		th4.start();
	}
}
728x90
반응형

댓글