025 Semaphore

강의 메모 - Semaphore - 세마포어 - 1,2 #

개요 #

  • 세마포어는 공유 자원에 대한 접근을 제어하기 위해 사용되는 신호전달 메커니즘 동기화 도구이다
    • Mutex는 락을 획득한 쓰레드가 락을 해제 할 수 있음
    • 세마포어 : 신호전달로, 쓰레드가 임계영역에 들어갈 수 있도록 락을 풀어주거나 하나가 아닌 여러 쓰레드가 락을 동시에 가질 수 있다.
  • 세마포어는 정수형 변수 S 와 P(Proberen: try), V(Verhogen: increment)의 두 가지 원자적 함수로 구성된 신호전달 메커니즘 동기화 도구이다
    • P : 임계 영역을 사용하려는 스레드의 진입 여부를 결정하는 연산, Wait 연산이라고도 함
      • 락을 획득하는것
    • V : 대기 중인 프로세스를 깨우는 신호(Wake-up)로 Signal 연산
      • 락을 획득하고 연산한 이후, 락을 해제하는것
  • 스레드가 임계영역에 진입하지 못할 경우 자발적으로 ‘대기(BLOCK)‘상태에 들어가고 임계영역을 빠져나오는 스레드가 대기상태의 스레드를 실행대기상태로 깨워준다
  • 자바에서는 java.util.concurrent 패키지에 세마포어 구현체를 포함하고 있기 때문에 직접 세마포어를 구현할 필요는 없다 세마포어는 특정 신호에 의해 공유자원의 접근을 제어하고 보호하는 신호체계 동기화 도구이다

세마포어 #

  1. S
  • 의미 : 정수형 변수
  • 설명 : 공유 자원의 개수로서, 이 개수 만큼 스레드의 접근이 허용된다.
  1. P (wait)
  • 의미 : S가 1감소 (S–)
  • 설명 : 스레드가 임계 구역에 진입하기 전 실행되어 카운트의 값을 1 감소시킨다.
  1. V
  • 의미 : S가 1 증가 (S++)
  • 설명 : 스레드가 임계 구역에서 빠져나올때 실행되어 카운트의 값을 1 증가시킨다.

동기화

  • S > 0 : 공유 자원 접근 허용
  • S = 0 : 공유 자원 접근 불가
  • 같은 세마포어의 P, V 함수의 S 연산은 여러 스레드간 동시에 실행이 되지 않도록 원자적 실행이 보장되어야한다. img.png

P(wait) 동작 방식 #

  • S = 2일 때 2개의 쓰레드가 임계영역에 진입될 수 있다
  • thread A 1개가 진입되면 S– 수행되어 S = 1이 된다.
  • thread B도 wait()을 통해서 임계영역 진입을 위해 세마포어를 얻는다. s– 수행되어 S = 0
  • 최종적으로 세마포어 S = 0
  • 0이 된 이후로 다른 쓰레드가 최소한 하나라도 해제를 해야 세마포어를 얻을 수 있게된다.
  • thread C가 wait() 호출하면 blocked 된다.

V(signal) 동작 방식 #

  • threadA, threadB가 세마포어를 얻어서 S = 0이고, thread C는 세마포어를 획득할 수 없으므로 blocked 상태
  • thread A가 세마포어를 릴리즈하여 S++ 수행되어 S = 1
  • thread C가 이제 진입 가능, 세마포어 S– 수행되어 S = 0 (threadB, threadC가 수행중)
  • 모든 스레드가 릴리즈 수행
  • 그럼 다시 세마포어는 S = 2로 초기화
  • threadD, threadE가 wait() 호출하여 임계영역에 들어가기 위한 허가권을 얻음
  • S 는 최종적으로 0이됨

세마포어 유형 #

  • 세마포어는 카운트 변수 S 가 1인 이진 세마포어(Binary Semaphore) 와 2 이상의 양수 값을 가진 카운팅 세마포어(Counting Semaphore)로 구분할 수 있다.
    • 이진 세마포어(Binary Semaphore) : 뮤텍스랑 거의 동일
    • 카운팅 세마포어(Counting Semaphore) : signal(카운터 변수)을 변경하는 쓰레드가 꼭 본인이 아니여도된다.

이진 세마포어 #

  • 세마포어를 뮤텍스 처럼 락으로 사용하기 위해서는 카운트 변수를 1로 설정하고 한 스레드 안에서 세마포어를 회득하고 해제 할 수 있도록 구현한다
  • 한 스레드만이 세마포어를 획득할 수 있기 때문에 그 외 다른 모든 스레드가 acquired()를 호출하게 되면 해당 스레드가 세마포어를 해제하기 전까지 블록된다

카운팅 세마포어 #

  • 카운팅 세마 포어는 카운트 변수를 설정해서 스레드가 공유할 수 있는 자원의 최대치를 한정해서 운용하는 방식으로 자원 풀(pool)이나 컬렉션의 크기에 제한을 두고자 할 때 유용하다
    • DB Connection 개수 제한, 파일 다운로드 동시 실행 제한 등..
  • 락을 획득한 스레드와 락을 해제하는 스레드는 다를 수 있으며 스레드 간 락과 락해제를 위한 신호를 전달함으로 동기화를 구현한다

자바 세마포어 구조 #

img_1.png

  • 공정성 여부가 true이면 원래 스케줄링해서 진행했던 부분을 wait 요청한 순으로 할당함

자바 세마포어 사용 #

  • 인수로 전달하는 초기 허가 수는 런타임에서 동적으로 변경 가능하다
  semaphore.acquire();
  임계영역;
  semaphore.release();

뮤텍스와 세마포어 #

  • 동작 방식
    • 뮤텍스는 공유 자원에 대한 접근을 동시에 하나의 스레드만 가능하도록 보장한다. 즉, 뮤텍스는 상호 배제를 위한 동기화 기법이다
    • 세마포어는 카운팅 기법으로, 특정 개수의 스레드가 동시에 공유 자원에 접근할 수 있도록 제어한다.
    • 0 또는 1의 값을 가진 이진 세마포어는 뮤텍스와 유사한 역할을 하며 계수 세마포어는 양수 값을 가지며, 해당 개수만큼의 스레드가 동시에 접근을 허용한다
  • 소유권
    • 뮤텍스는 소유권이 있어서 락을 획득한 스레드만이 락을 해제할 수 있다. 즉, 락을 획득한 스레드가 락을 해제하지 않으면 다른 스레드는 해당 뮤텍스에 접근할 수 없다.
    • 세마포어는 소유권이 없으며, 특정 개수의 스레드가 동시에 접근을 허용하는 카운팅 기법으로 작동한다. 따라서 세마포어를 사용하는 스레드들이 모두 세마포어를 해제할 수 있다.
  • 초기값
    • 뮤텍스는 기본적으로 잠겨있는 상태로 시작한다. 한 스레드가 뮤텍스를 획득하여 자원에 접근하면 다른 스레드들은 해당 뮤텍스를 획득하기 위해 블로킹된다
    • 세마포어는 초기값을 설정할 수 있으며 초기값에 따라서 처음부터 스레드가 자원에 접근할 수 있는지 여부가 결정된다
  • 사용 목적
    • 뮤텍스는 주로 상호 배제를 위해 사용되며 하나의 자원에 하나의 스레드만 접근하도록 보장해야 하는 경우에 사용된다
    • 세마포어는 주로 리소스의 한정적인 사용을 제어하는 데 사용되며 특정 개수의 스레드만이 동시에 자원에 접근하도록 제한하고자 할 때 사용된다
  • 자바에서는 뮤텍스를 고도화한 모니터 객체와 세마포어 구현체를 제공하고 있다