경쟁 상태
여러 프로세스들이 동시에 데이터에 접근하는 상황에서, 어떤 순서로 접근하냐에 따라 결과 값이 달라지는 것을 경쟁 상태(Race Condition)이라고 한다.
이러한 문제를 방지하기 위해 동기화 기법이 사용되며, 이때 공유 자원에 접근하는 코드가 임계 구역(Critical Section)이다.
Critical Section Problem(임계 구역 문제)
임계 구역은 하나의 프로세스나 스레드만 들어갈 수 있는 코드 영역이다.
예를 들어, 여러 스레드가 같은 메모리 영역에 값을 쓰려고 하면 충돌이 발생할 수 있는데, 이때 각 스레드가 동시에 해당 메모리 영역을 쓰지 않도록 보호해야 한다.
이러한 설계를 위해서는 3가지 요구조건을 만족해야 한다.
1. Mutual Exclusion(상호 배제)
하나의 프로세스 또는 스레드(이하 task)가 임계 구역에서 작업 중이면 다른 task는 그 임계 구역에 진입할 수 없다.
2. Progess(진행 조건)
현재 임계 구역에서 작업 중인 task가 없는 상태에서, 임계 구역에 들어가고자 하는 task가 있으면 진입할 수 있어야 한다.
3. Bounded Waiting(한정 대기)
어떤 task가 임계 구역에 들어가려 할 때 무한 대기하지 않도록 한정된 대기시간을 가져야 한다.
Critical Section Problem를 해결하는 동기화 기법
임계 구역 문제를 해결하기 위해 여러 가지 동기화 기법이 존재한다.
그중 뮤텍스 락과 세마포어, 모니터 3가지 소프트웨어적인 방법을 알아보자.
1. Mutex Lock(뮤텍스 락)
한 번에 하나의 스레드만이 공유 자원에 접근할 수 있도록 하는 락(Lock) 메커니즘이다.
- - 자물쇠 역할 : 프로세스들이 공유하는 전역 변수 lock
- - 임계 구역을 잠그는 역할 : acquire 함수
- - 임계 구역의 잠금을 해제하는 역할 : release 함수
while(true){
acquire();
/* Critical Section*/
release();
/* Remainder Section*/
}
acquire(){ // 사용가능 해지면 크리티컬 섹션에 들어간후 문을 잠금!
while(!available) // Busy Waiting
available = false;
}
release(){ // 사용가능 하게 해줌
available = true;
}
task가 임계 구역에 들어갈 때 락을 획득하고, 빠져나올 때 락을 해제한다.
ex) 화장실에 칸이 1개이고, 들어갈 때 열쇠를 가져가야 한다.
문제점은 Busy Waiting으로 인해 효율이 발생한다.
Busy Waiting(Spin Lock)
`while(!available)`을 보면 Lock이 반환될 때까지 계속 확인하면서 프로세스가 기다리는 것을 말한다.
2. Semaphore(세마포어)
공유 자원에 접근할 수 있는 스레드의 수를 제한하는 동기화 기법이다.
세마포어는 카운터라는 정수형 변수(S)를 사용해 임계 구역에 진입할 수 있는 task를 제한한다.
한 프로세스가 세마포어 변수를 수정할 때 다른 프로세스가 동시에 같은 세마포어 변수를 수정할 수 없다.
세마포어의 주요 연산
세마포어는 두 가지 주요 연산을 가지고 있다.
1. P(S) 또는 `wait()`: 세마포어 값을 감소시키는 연산
wait() { // 사용가능 해지면 크리티컬 섹션에 들어간후 문을 잠금!
while(S <= 0) // Busy Waiting
available = false;
}
세마포어 값이 0이상이면, 값을 1 감소시키고 스레드는 임계 구역에 들어갈 수 있다.
세마포어 값이 0이면, 스레드는 대기 상태에 놓인다.
2. V(S) 또는 `signal()`: 세마포어 값을 증가시키는 연산
signal() {
S++;
}
임계 구역에서 작업이 끝난 스레드가 세마포어 값을 증가시켜, 다른 대기 중인 스레드가 임계 구역에 들어갈 수 있게 한다.
세마포어의 종류
세마포어의 종류는 크게 2가지로 나눌 수 있다.
- 이진 세마포어(Binary Semaphore)
- 값이 0 또는 1만 가질 수 있는 세마포어로, 뮤텍스(Mutex)와 유사한 방식으로 동작한다.
- 자원에 한 번에 하나의 스레드만 접근할 수 있도록 제한한다.
- 세마포어 값이 1이면 자원을 사용할 수 있고, 값이 0이면 다른 스레드가 자원을 사용 중임을 의미한다.
- 계수 세마포어(Counting Semaphore)
- 값이 0 이상의 정수 값을 가질 수 있는 세마포어로, 여러 스레드가 동시에 자원에 접근할 수 있도록 제한한다.
- 예를 들어, 세마포어 값이 3이면 최대 3개의 스레드가 동시에 자원에 접근할 수 있습니다.
세마포어 값이 0이 되면, 더 이상 스레드가 자원에 접근할 수 없고, 자원이 해제되기를 기다린다.
세마포어의 단점
데드락(교착 상태)
교착 상태란 상호 배제에 의해 나타나는 문제점으로, 두 개 이상의 프로세스가 서로가 필요로 하는 자원을 점유하고 있어 서로의 작업이 영원히 진행되지 않는 상황을 말한다.
S와 Q가 각각 1로 초기화된 바이너리 세마포어일 때, 위와 같은 순서로 바이너리 세마포어를 호출할 때 S와 Q가 각각 0이 된다.
이후에 두 프로세스가 모두 블록 되어 데드락이 발생한다.
바쁜 대기(busy wait)의 단점 극복
wait 함수는 사용할 수 있는 공유 자원이 없는 경우 프로세스는 무작정 무한히 반복하며 S를 확인해야 한다.
이는 CPU 사이클을 낭비한다는 점에서 손해이다.
그래서 세마포는 아래와 같은 방법으로 이를 해결한다.
- 사용할 수 있는 자원이 없을 경우 대기 상태로 만듦(해당 프로세스의 PCB를 대기 큐에 삽입)
- 사용할 수 있는 자원이 생겼을 경우 대기 큐의 프로세스를 준비 상태로 만듦(해당 프로세스의 PCB를 대기 큐에서 꺼내 준비 큐에 삽입)
뮤텍스(Mutex)와 세마포어(Semaphore)의 차이
뮤텍스(Mutex)는 한 번에 하나의 task만 자원에 접근할 수 있는 동기화 기법으로 이진 세마포어와 유사하지만,
뮤텍스는 소유권 개념이 있어서 자원을 사용한 task만 자원을 해제할 수 있다.
세마포어(Semaphore)는 여러 스레드가 동시에 자원에 접근할 수 있으며, 동시에 접근할 수 있는 스레드의 수를 제한할 수 있다.
세마포어는 소유권 개념이 없어서 자원을 해제할 때 다른 스레드가 해제할 수도 있다.
3. Monitor(모니터)
세마포어의 단점을 해결하기 위한 기법으로 대표적으로 자바에서 `Synchronized` 키워드가 모니터락을 사용하는 예다.
모니터락(이하 모니터)은 위의 그림처럼 공유 자원에 접근하고자 하는 프로세스를 큐에 삽입하고, 큐에 삽입된 순서대로 하나씩 공유자원을 이용하도록 한다.
이때 모니터는 공유 자원을 내부적으로 숨기고 공유 자원에 접근하기 위한 인터페이스만 제공함으로써 자원을 보호하고 프로세스 간에 동기화를 시킨다.
모니터는 시스템 호출과 같은 개념이다.
운영체제가 관리하는 자원을 사용자가 마음대로 사용하게 두면 실수나 악의적인 의도로 시스템 자원을 망가뜨릴 수 있다.
이러한 문제를 예방하기 위해 운영체제는 시스템 자원을 사용자로부터 숨기고 사용자의 요구 사항을 처리할 수 있는 인터페이스만 제공하는데, 이를 시스템 호출이라고한다.
'👶🏻 CS > Operating System' 카테고리의 다른 글
교착상태와 해결법 (0) | 2024.11.15 |
---|---|
캐시 (0) | 2024.11.12 |
Concurrent(동시성) vs Parallel(병렬성) (0) | 2024.11.09 |
가상메모리와 페이지 교체 알고리즘 (0) | 2024.11.08 |
프로세스와 스레드 (0) | 2024.11.07 |
Sync&Async, Blocking&Non-Blocking (0) | 2024.10.31 |