동시성 문제
두 개 의상의 세션이 공통된 자언에 대해 모두 읽고 쓰는 작업 (Read → Write)를 할 때 발생하는 문제를 뜻한다.
Critical Section
임계구역이라 하는 Critical Section은 한 번에 하나의 프로세스만 액세스 할 수 있는 코드 영역을 의미한다.
프로세스는 일반적으로 4가지의 코드 영역으로 나뉜다.
- Entry Section
- Critical Section에 진입하기 위해 진입허가 요청을 하는 영역이다.
- Critical Section에 진입하는것을 제어한다 하는데 이를 Lock한다고 한다.
- Ciritical Section
- 하나의 프로세스만 접근할 수 있는 영역이다.
- Exit Section
- Lock을 해제하는 등, 더이상 Critical Section에 존재하지 않을 때 알리는 역할을 한다.
- Reminder Section
- 입력 섹션, 중요 섹션 및 종료 섹션을 제외한 코드의 다른 부분을 나머지 섹션이라고 한다.
Critical Section(임계 구역)에는 둘 이상의 프로세스가 동시에 접근을 할 수 없다.
각 프로세스별로 자신의 임계구역에 들어가기 위해서는 Entry Section에서 진입 허가를 받고 접근을 해야한다.
만약, 여러 프로세스가 동시에 임계구역에 접근을 하려고 한다면 Race Condition이 발생을 한다.
Race Condition
두 개 이상의 프로세스가 공통 자원을 병행적으로(concurrently) 읽거나 쓰는 동작을 할 때, 공용 데이터에 대한 접근이 어떤 순서에 따라 이루어졌는지에 따라 그 실행 결과가 같지 않고 달라지는 상황을 말한다.
Race의 뜻 그대로, 간단히 말하면 경쟁하는 상태, 즉 두 개의 스레드가 하나의 자원을 놓고 서로 사용하려고 경쟁하는 상황을 말한다.
Race Condition의 3가지 제어 문제
Mutual exclusion
Race condition을 막기 위해서는 두 개 이상의 프로세스가 공용 데이터에 동시에 접근을 하는 것을 막아야 한다.
즉, 한 프로세스가 공용 데이터를 사용하고 있으면 그 자원을 사용하지 못하도록 막거나, 다른 프로세스가 그 자원을 사용하지 못하도록 막으면 이 문제를 피할 수 있다. 이것을 상호 배제(mutual exclusion)라고 부른다.
Deadlock
그러나 위와 같은 상호 배제를 시행하면 추가적인 제어 문제가 발생한다.
하나는 교착상태(Deadlock)이다.
프로세스가 각자 프로그램을 실행하기 위해 두 자원 모두에 엑세스 해야 한다고 가정할 때 프로세스는 두 자원 모두를 필요로 하므로 필요한 두 리소스를 사용하여 프로그램을 수행할 때까지 이미 소유한 리소스를 해제하지 않는다.
이러한 상황에서 두 프로세스는 교착 상태에 빠지게 되는 문제가 발생할 수 있다.
Starvation
이 제어 문제는 ‘기아 상태’라고도 한다.
이러한 문제는 프로세스들이 더 이상 진행을 하지 못하고 영구적으로 블록되어 있는 상태로, 시스템 자원에 대한 경쟁 도중에 발생할 수 있고 프로세스 간의 통신 과정에도 발생할 수 있는 문제이다.
두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있기 때문에 결과적으로는 아무것도 완료되지 못하는 상태가 되게 된다.
이렇게 Race condition 인 경우에는 스레드의 실행 순서를 잘 조절해주지 않으면 이상한 상태, 비정상적인 상태가 나오게 된다.
이 문제는 항상 발생하는 것이 아니라 특정한 순서대로 수행되었을 때 발생하는 것이다.
이 문제는 디버깅을 할 때에는 전혀 보이지 않는 문제점이고, 발생 시에 모든 프로세스에 원하는 결과가 발생하는 것을 보장할 수 없으므로 후에 더욱 큰 문제를 야기할 수 있으므로 반드시 피해야 하는 상황이다.
이러한 문제가 발생하지 않도록, OS는 다른 프로세스의 의도하지 않은 간섭으로부터 각 프로세스의 데이터 및 물리적 자원을 보호해야 하며 여기에 메모리, 파일 및 I/O 장치와 관련된 내용이 포함된다.
그리고 프로세스에서 수행하는 내용과 프로세스가 생성하는 결과는, 다른 동시 프로세스의 실행 속도와 무관, 즉 기능과 결과는 서로 독립적이어야 한다.
Race Condition 예방 방법
Semaphore(세마포어)
공유된 자원의 데이터를 여러 프로세스가 접근하는 것을 막는 것이다.
또한 세마포어는 리소스의 상태를 나타내는 간단한 카운터라고 할 수 있는데,
일반적으로 비교적 긴 시간을 확보하는 리소스에 대해 이용하게 되며, 운영체제의 리소스를 경쟁적으로 사용하는 다중 프로세스에서 행동을 조정하거나 동기화 시키는 기술이다.
다시 말해서 하나의 스레드만 들어가게 할 수도 있고 여러 개의 스레드가 들어가게 할 수 있다.
Mutex(뮤텍스)
공유된 자원의 데이터를 여러 스레드가 접근하는 것을 막는 방법이다.
즉, Critical Section을 가진 쓰레드들의 Running time이 서로 겹치지 않게 각각 단독으로 실행되게 하는 기술이다.
다중 프로세스들이 공유 리소스에 대한 접근을 조율하기 위해 locking과 unloking을 사용하는데,
상호배제를 함으로써 두 쓰레드가 동시에 사용할 수 없다는 뜻이다.
Semaphore(세마포어) vs Mutex(뮤텍스)
- Mutex는 동기화 대상이 오직 1개일 때 사용하며, Semaphore는 동기화 대상이 1개 이상일 때 사용한다.
- Mutex는 자원을 소유할 수 있고, 책임을 가지는 반면 Semaphore는 자원 소유가 불가능하다.
- Mutex는 상태가 0, 1뿐이므로 Lock을 가질 수 있고 소유하고 있는 스레드만이 이 Mutex를 해제할 수 있다.
- Semaphore는 Semaphore를 소유하지 않는 스레드가 Semaphore를 해제할 수 있다.
- Semaphore는 시스템 범위에 걸쳐 있고 파일 시스템 상의 파일로 존재한다. 반면 Mutex는 프로세스의 범위를 가지며 프로세스가 종료될 때 자동으로 Clean up 된다.