1. 임계영역
임계영역은 둘 이상의 프로세스나 쓰레드가 동시에 동일한 자원에 접근하게 되는 프로그램 코드 부분을 의미하는데 각 프로세스나 쓰레드가 임계구역에서 일을 수행하는 동안 다른 프로세스나 쓰레드가 그 임계영역에 들어갈 수 없어야 한다. 즉, 임계영역 내의 코드는 원자적 실행이 되야 하는 것이다.
이렇듯, 원자적으로 실행되기 위해 임계영역으로 들어갈 때 entry section을 통해 진입 허가를 요청하게 되고 허가 요청이 수락되면 임계영역을 실행하게 된다. 임계영역에서 수행이 끝나면 exit section으로 퇴출하게 된다.
임계영역의 원자성을 보장함으로써 프로세스나 쓰레드들이 동기화 되도록 할 수 있고 이러한 방법 중 대표적인 방법이 뮤텍스와 세마포어인 것이다.
2. 동기화
멀티 쓰레드인 경우 서로 다른 쓰레드가 프로세스의 메모리를 공유하기 때문에 동시에 자원에 접근하는 상황(경쟁 상황)이 생기게 되는데 이런 경쟁 상황으로 인해 발생하는 문제가 동기화 문제이다.
이런 문제로부터 보호하기 위해 하나의 프로세스 혹은 하나의 쓰레드만이 한 자원에 접근할 수 있게 해야 한다.
2개의 스레드가 count라는 변수에 접근해서 1씩 증가하는 연산을 한다고 가정해봅시다. count값은 현재 1입니다.
스레드1이 접근해서 count의 값을 읽어옵니다. 다음으로 바로 스레드2가 접근해서 count 값을 읽어옵니다.
스레드1과 스레드2가 각각 count 값을 1을 증가 시켜 2로 만듭니다.
스레드1이 count에 2를 저장합니다.스레드2가 count에 2를 저장합니다.
원래 같으면 스레드1 과 2를 실행하고 나서 count의 값은 3이 되길 기대했지만 count의 값은 2입니다.
3. 멀티 프로세스 , 스레드 환경에서 동기화 문제 해결
Mutex(뮤텍스), Semaphore(세마포어) 방법을 사용하여 해결할 수 있다. 간단하게 말하면 뮤텍스는 한 개의 쓰레드만 공유 자원에 접근할 수 있게 해서 경쟁 상황을 방지하는 것이고, 세마포어는 지정한 수 만큼의 쓰레드만 공유 자원에 접근할 수 있게 하는 것이다.
뮤텍스 : 1개의 스레드만 공유자원에 접근가능합니다.
- 세마포어 : S개의 스레드만이 공유자원에 접근가능합니다. 스레드가 접근할 때 마다 S의 개수를 감소시키며 S가 0이라면 자원에 접근 할 수 없습니다.
4. Mutex, 뮤텍스
동기화 방법 중 하나로 공유 자원에 접근할 수 있는 프로세스 혹은 쓰레드를 1개로 제한한다. 한 쓰레드가 자원을 사용하는 동안 다른 쓰레드는 자원에 접근하지 못 하므로 대기를 하게 되는데 이런 대기를 하는 상황 때문에 CPU를 낭비한다는 단점이 있다.
쓰레드 A와 쓰레드 B가 있다고 가정한다.
1. 쓰레드 A가 공유 자원에 먼저 접근한다.
2. 공유 자원을 사용 중인 쓰레드 A는 다른 쓰레드가 접근하지 못 하도록 `lock`을 건다.
3. 이때, 쓰레드 B가 공유 자원에 접근한다.
4. 쓰레드 A가 걸어둔 `lock`에 의해 쓰레드 B는 공유 자원에 접근하지 못 하게 되고 쓰레드 A가 나오길 기다리면서 대기한다.
5. 쓰레드 A가 공유 자원을 다 사용하고 나오면서 `unlock`을 한다.
6. 이제, 기다리던 쓰레드 B가 공유 자원에 들어가게 되고 다른 쓰레드가 접근하지 못 하도록 `lock`을 건다.
acquire() // entry section
// critical section
release() // exit section
acquire() {
while(!available); // wait !
available = false;
}
release() {
available = true;
}
5. Semaphore, 세마포어
세마포어는 뮤텍스(단일)과 달리 여러 개의 쓰레드를 설정할 수 있다. 하지만 뮤텍스와 마찬가지로 단일 쓰레드만 공유 자원에 접근이 가능하도록 설정해 줄 수도 있는데 이러한 세마포어를 binary semaphore라고 하고 이 경우 뮤텍스처럼 작동하게 된다.
1. 정수형 변수 `s`(세마포)를 사용 가능한 자원의 수로 초기화한다.
2. 자원에 접근하면 `s--` 연산자를 통해 사용 가능한 자원의 수를 줄인다.
3. 자원을 다 사용하고 나가게 되면 `s++` 연산자를 통해 사원 가능한 자원의 수를 늘린다.
4. 세마포의 값이 `0`이 되면 모든 자원이 사용중인 것이기 때문에 세마포의 값이 `0`보다 커질 때 까지 대기해야 한다.
wait(S) // entry section
// critical section
signal(S) // exit section
wait(S) {
while(S<=0); // wait !
S--;
}
signal(S) {
S++;
}
6. 뮤텍스와 세마포어 차이
뮤텍스는 단일, 세마포어는 다수의 프로세스 혹은 쓰레드를 공유 자원에 접근 가능하도록 해준다. 하지만 세마포어를 단일 값으로 설정할 수 있는데 이 경우 바이너리 세마포어라고 하며 뮤텍스와 같다고 할 수 있다.