하루에 한 문제
세마포어(Semaphore) vs 뮤텍스(Mutex) 본문
동기화(Synchronization)
- 여러 프로세스나 쓰레드가 공유하는 자원의 일관성을 유지하는 것
- 여러 프로스세나 쓰레드가 동시에 하나의 자원에 접근할 때 접근 순서를 정해 일관성을 유지해준다.
Race Condition
- 두 개 이상의 동시성이 있는 프로세스나 스레드들이 동기화없이 공유된 자원에 접근하려는 현상
- 쉽게 말해 두 개 이상의 스레드가 하나의 자원을 놓고 서로 사용하려고 경쟁(race)하는 상황이다.
위 그림처럼 파란색과 빨간색이 동시에 balance라는 공통변수에 접근한다면 문제가 생기게 된다.
예를 들어 A라는 학생이 은행에 가서 10만원을 입금하는 동시에 A라는 학생의 엄마인 B가 20만원을 입금한다면??
=> 원래대로는 기본 돈 + 10 + 20 => 기본돈 + 30만원이 되어야 한다.
=> 하지만 동기화 문제가 발생하면 기본돈 +10 OR 기본돈 + 20 만원이 될것이다.
Critical Section(임계영역)
- 여러 개의 스레드가 수행되는 시스템에서 각 스레드들이 공유하는 데이터를 변경하는 코드 영역
- 임계영역을 통해서 Race Condition을 막을 수 있다.
- 3가지 조건이 필요하다. (상보 배제, 진행, 한정된 대기)
상호 배제(Mutual Exclusion)
- 한 스레드가 임계구역에서 수행중인 상태에서 다른 스레드는 접근 불가
진행 (Progress)
- 현재 기다리고 있는 스레드중 누가 먼저 들어갈 것인가에 대한 결정이 유한 시간 내에 일어나야 한다.
- 임계영역에 어떤 스레드도 없다면 기다리고 있는 스레드는 무조건 임계영역에 진입가능해야 한다.
한정된 대기 (Bounded waiting)
- 임계구역으로 진입하기 위해 대기하는 모든 쓰레드는 유한 시간 이내에 해당 임계구역으로 진입할 수 있어야 한다.
- 기아상태를 피하기 위해 한번 임계영역에 들어간 스레드가 다시 임계영역에 들어갈 때는 제한을 두어야 한다.
뮤텍스 (Mutex)
- 뮤텍스는 화장실이 하나밖에 없는 식당이라고 생각하면 편하다.
- 화장실을 가기 위해서는 카운터에서 열쇠를 받아가야 한다.
- 만약 당신이 화장실을 가려고 하는데 카운터에 키가 있으면 화장실에 사람이 없다는 뜻이기 때문에 바로 화장실로 갈 수 있다.
- 당신이 화장실에서 좋은 시간을 보내는 도중 식당의 다른 손님이 화장실에 가고 싶어한다.
- 하지만 카운터에 키가 없기 때문에 화장실에 들어갈 수 없다.
- 결국 당신이 나올 때 까지 기다렸다가 카운터에서 키를 받아가는 수 밖에 없다.
- 곧 이어 옆 테이블의 사람도 화장실이 가고싶어졌다... 이 남자 또한 화장실에 들어가기 위해서는 기다려야한다.
- 당신이 화장실에서 나온 뒤 카운터에 키를 돌려 놓게되면 기다리던 사람 중 맨앞에 있던 사람이 키를 받아 화장실을 사용할 수 있다.
- 이것이 뮤텍스가 동작하는 방식이다. 화장실을 이용하는 사람은 프로세스 or 스레드 이며 화장실은 공유자원, 화장실 키는 공유자원에 접근하기 위해 필요한 어떤 오브젝트 라고 생각할 수 있다.
- 즉 뮤텍스는 Key에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 스레드or프로세스 만이 공유자원에 접근이 가능하다.
뮤텍스는 자원에 대한 접근을 동기화하기 위해 사용되는 상호배제 기술이다.
- 뮤텍스는 Locking 메커니즘으로 오직 하나의 쓰레드만이 동일한 시점에 뮤텍스를 얻어 임계 영역(Critical Section)에 접근할 수 있다.
- 그리고 오직 이 스레드만이 임계 영역에서 나갈 때 뮤텍스를 해제할 수 있다.
acquire();
......
Critical Section
......
release();
acquire(){
while(!available)
/*busyWaitting*/
available = false;
}
release(){
available
}
위의 수도코드는 뮤텍스의 과정을 보여주는데, 락을 얻은 쓰레드만이 임계 영역을 나갈 때 락을 해제할 수 있다.
이러한 이유는 뮤텍스는 1개의 락만을 가지는 Locking 메커니즘이기 때문이다!
세마포어(Semaphor)
- 세마포어는 화장실이 여러개인 식당이라고 생각하면 편하다.
- 그리고 화장실 입구에는 현재 몇개의 화장실이 비었는지 보여주는 전광판이 있다.
- 만약 당신이 화장실에 가고 싶다면 전광판에서 빈 칸의 개수를 확인하고 빈칸이 1개 이상일면 빈 칸의 개수를 하나 줄이고 화장실로 입장해야 한다.
- 그리고 나올 때는 당연히 빈 칸의 개수를 하나 올려주고 나오면 된다.
- 모든 칸에 사람이 차있을 경우 빈 칸의 개수는 0이 되며 이때 화장실에 들어가고 하는 사람이 있다면 빈 칸의 개수가 1로 바뀔때까지 기다려야 한다.
- 사람들은 나오면서 빈 칸의 개수를 1씩 더한다. 그리고 기다리선 사람은 이 숫자에서 다시 1을 뺀 다음 화장실로 달려간다.
- 이처럼 세마포어는 공통으로 관리하는 하나의 값을 이용해 상호배제를 달성한다.
- 세마포어도 뮤텍스와 같이 똑같이 화장실이 공유자원이며 사람들이 스레드or프로세스이다.
- 그리고 화장실 빈칸의 개수는 현재 공유 자원에 접근할 수 있는 스레드or프로세스의 개수를 나타낸다.
세마포어는 Signaling 메커니즘이라는 점에서 뮤텍스와 다르다.
세마포어는 락을 걸지 않은 쓰레드도 Signal을 보내 락을 해제할 수 있다는 점에서, wait 함수를 호출한 쓰레드만이 signal 함수를 호출할 수 있는 뮤텍스와 다르다.
세마포어는 동기화를 위해 wait와 signal이라는 2개의 atomic operations를 사용한다.
wait를 호출하면 세마포어의 카운트를 1줄이고, 세마포어의 카운트가 0보다 작거나 같아질 경우에 락이 실행된다.
최초 제시된 방법은 Busy-waiting을 활용한 방법이다.
P(S) {
while S <=0; // 아무것도 하지 않음 (반복문)
S--;
}
V(S) {
S++;
}
이 방법은 임계구역에 진입하기 전 까지 계속해서 빈 반복문을 수행함으로 효율이 떨어진다.
이 단점을 보완해 '큐 or 리스트'를 활용한 방법이 있다.
P(S) {
S--;
if S < 0
block();
}
V(S) {
S++;
if S <= 0
wakeUp();
}
- 세마포어의 카운트가 0보다 작거나 같아져 동기화가 실행된 상황에, 다른 쓰레드가 signal 함수를 호출하면 세마포어의 카운트가 1증가하고, 해당 쓰레드는 락에서 나올 수 있다.
- 세마포어는 크게 Counting Semaphores, Binary Semaphore 2종류가 있다.
- 카운팅 세마포어는 세마포어의 카운트가 양의 정수값을 가지며, 설정한 값만큼 쓰레드를 허용하고 그 이상의 쓰레드가 자원에 접근하면 락이 실행된다.
- 바이너리 세마포어는 세마포어의 카운트가 1이며 Mutex처럼 사용될 수 있다.
- (뮤텍스는 절대로 세마포어처럼 사용될 수 없다.)
뮤텍스와 세마포어의 차이
- 세마포어는 자원의 상태를 나타내는 일종의 '변수'로써 소유 개념이 아니지만, 뮤텍스는 자원을 점유한 프로세스나 쓰레드가 잠시 소유하였다가 작업이 끝나면 반환하는 개념이다.
- 뮤텍스는 Locking 메커니즘으로 락을 걸은 쓰레드만이 임계 영역을 나갈때 락을 해제할 수 있다. 하지만 세마포어는 Signaling 메커니즘으로 락을 걸지 않은 쓰레드도 signal을 사용해 락을 해제할 수 있다.
- 가장 큰 차이점은 뮤텍스가 동기화 대상이 자원의 하나라면, 세마포어는 하나 이상일 때 사용된다.
- 세마포어는 뮤텍스가 될 수 있지만 뮤텍스는 절대로 세마포어가 될 수 없다.
참조
https://dduddublog.tistory.com/25
https://mangkyu.tistory.com/104