강의 메모 - Semaphore - 세마포어 - 1,2 #
개요 #
- 세마포어는 공유 자원에 대한 접근을 제어하기 위해 사용되는 신호전달 메커니즘 동기화 도구이다
- Mutex는 락을 획득한 쓰레드가 락을 해제 할 수 있음
- 세마포어 : 신호전달로, 쓰레드가 임계영역에 들어갈 수 있도록 락을 풀어주거나 하나가 아닌 여러 쓰레드가 락을 동시에 가질 수 있다.
- 세마포어는 정수형 변수 S 와 P(Proberen: try), V(Verhogen: increment)의 두 가지 원자적 함수로 구성된 신호전달 메커니즘 동기화 도구이다
- P : 임계 영역을 사용하려는 스레드의 진입 여부를 결정하는 연산, Wait 연산이라고도 함
- 락을 획득하는것
- V : 대기 중인 프로세스를 깨우는 신호(Wake-up)로 Signal 연산
- 락을 획득하고 연산한 이후, 락을 해제하는것
- P : 임계 영역을 사용하려는 스레드의 진입 여부를 결정하는 연산, Wait 연산이라고도 함
- 스레드가 임계영역에 진입하지 못할 경우 자발적으로 ‘대기(BLOCK)‘상태에 들어가고 임계영역을 빠져나오는 스레드가 대기상태의 스레드를 실행대기상태로 깨워준다
- 자바에서는 java.util.concurrent 패키지에 세마포어 구현체를 포함하고 있기 때문에 직접 세마포어를 구현할 필요는 없다 세마포어는 특정 신호에 의해 공유자원의 접근을 제어하고 보호하는 신호체계 동기화 도구이다
세마포어 #
- S
- 의미 : 정수형 변수
- 설명 : 공유 자원의 개수로서, 이 개수 만큼 스레드의 접근이 허용된다.
- P (wait)
- 의미 : S가 1감소 (S–)
- 설명 : 스레드가 임계 구역에 진입하기 전 실행되어 카운트의 값을 1 감소시킨다.
- V
- 의미 : S가 1 증가 (S++)
- 설명 : 스레드가 임계 구역에서 빠져나올때 실행되어 카운트의 값을 1 증가시킨다.
동기화
- S > 0 : 공유 자원 접근 허용
- S = 0 : 공유 자원 접근 불가
- 같은 세마포어의 P, V 함수의 S 연산은 여러 스레드간 동시에 실행이 되지 않도록 원자적 실행이 보장되어야한다.
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 개수 제한, 파일 다운로드 동시 실행 제한 등..
- 락을 획득한 스레드와 락을 해제하는 스레드는 다를 수 있으며 스레드 간 락과 락해제를 위한 신호를 전달함으로 동기화를 구현한다
자바 세마포어 구조 #
- 공정성 여부가 true이면 원래 스케줄링해서 진행했던 부분을 wait 요청한 순으로 할당함
자바 세마포어 사용 #
- 인수로 전달하는 초기 허가 수는 런타임에서 동적으로 변경 가능하다
semaphore.acquire();
임계영역;
semaphore.release();
뮤텍스와 세마포어 #
- 동작 방식
- 뮤텍스는 공유 자원에 대한 접근을 동시에 하나의 스레드만 가능하도록 보장한다. 즉, 뮤텍스는 상호 배제를 위한 동기화 기법이다
- 세마포어는 카운팅 기법으로, 특정 개수의 스레드가 동시에 공유 자원에 접근할 수 있도록 제어한다.
- 0 또는 1의 값을 가진 이진 세마포어는 뮤텍스와 유사한 역할을 하며 계수 세마포어는 양수 값을 가지며, 해당 개수만큼의 스레드가 동시에 접근을 허용한다
- 소유권
- 뮤텍스는 소유권이 있어서 락을 획득한 스레드만이 락을 해제할 수 있다. 즉, 락을 획득한 스레드가 락을 해제하지 않으면 다른 스레드는 해당 뮤텍스에 접근할 수 없다.
- 세마포어는 소유권이 없으며, 특정 개수의 스레드가 동시에 접근을 허용하는 카운팅 기법으로 작동한다. 따라서 세마포어를 사용하는 스레드들이 모두 세마포어를 해제할 수 있다.
- 초기값
- 뮤텍스는 기본적으로 잠겨있는 상태로 시작한다. 한 스레드가 뮤텍스를 획득하여 자원에 접근하면 다른 스레드들은 해당 뮤텍스를 획득하기 위해 블로킹된다
- 세마포어는 초기값을 설정할 수 있으며 초기값에 따라서 처음부터 스레드가 자원에 접근할 수 있는지 여부가 결정된다
- 사용 목적
- 뮤텍스는 주로 상호 배제를 위해 사용되며 하나의 자원에 하나의 스레드만 접근하도록 보장해야 하는 경우에 사용된다
- 세마포어는 주로 리소스의 한정적인 사용을 제어하는 데 사용되며 특정 개수의 스레드만이 동시에 자원에 접근하도록 제한하고자 할 때 사용된다
- 자바에서는 뮤텍스를 고도화한 모니터 객체와 세마포어 구현체를 제공하고 있다