★KEYWORD★
레이스 컨디션 / 경쟁하는 상태 / 두 개 이상의 프로세스가 공통 자원을 병행으로 읽거나 쓰는 동작을 할 때 순서에 따라 실행결과가 달라지는 것 / 상호배제 / 데드락 / 기아상태 / 세마포어 / 뮤텍스
Race Condition 이란?
두 개 이상의 프로세스가 공통 자원을 병행적으로(concurrently) 읽거나 쓰는 동작을 할 때, 공용 데이터에 대한 접근이 어떤 순서에 따라 이루어졌는지에 따라 그 실행 결과가 같지 않고 달라지는 상황을 말한다.
Race의 뜻 그대로, 간단히 말하면 경쟁하는 상태, 즉 두 개의 스레드가 하나의 자원을 놓고 서로 사용하려고 경쟁하는 상황을 말한다.
경쟁 프로세스의 경우, 세 가지 제어 문제에 직면한다.
Mutual exclusion, deadlock, starvation이다.
Mutual exclusion (상호 배제)
Race condition을 막기 위해서는 두 개 이상의 프로세스가 공용 데이터에 동시에 접근을 하는 것을 막아야 한다. 즉, 한 프로세스가 공용 데이터를 사용하고 있으면 그 자원을 사용하지 못하도록 막거나, 다른 프로세스가 그 자원을 사용하지 못하도록 막으면 이 문제를 피할 수 있다. 이것을 상호 배제(mutual exclusion)라고 부른다.
Deadlock
그러나 위와 같은 상호 배제를 시행하면 추가적인 제어 문제가 발생한다. 하나는 교착상태, 여기서 말하는 Deadlock이다.
프로세스가 각자 프로그램을 실행하기 위해 두 자원 모두에 엑세스 해야 한다고 가정할 때 프로세스는 두 자원 모두를 필요로 하므로 필요한 두 리소스를 사용하여 프로그램을 수행할 때까지 이미 소유한 리소스를 해제하지 않는다.
이러한 상황에서 두 프로세스는 교착 상태에 빠지게 되는 문제가 발생할 수 있다.
Starvation
이 제어 문제는 ‘기아 상태’라고도 한다. 이러한 문제는 프로세스들이 더 이상 진행을 하지 못하고 영구적으로 블록되어 있는 상태로, 시스템 자원에 대한 경쟁 도중에 발생할 수 있고 프로세스 간의 통신 과정에도 발생할 수 있는 문제이다. 두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있기 때문에 결과적으로는 아무것도 완료되지 못하는 상태가 되게 된다.
이렇게 race condition 인 경우에는 스레드의 실행 순서를 잘 조절해주지 않으면 이상한 상태, 비정상적인 상태가 나오게 된다. 이 문제는 항상 발생하는 것이 아니라 특정한 순서대로 수행되었을 때 발생하는 것이다.
이 문제는 디버깅을 할 때에는 전혀 보이지 않는 문제점이고, 발생 시에 모든 프로세스에 원하는 결과가 발생하는 것을 보장할 수 없으므로 후에 더욱 큰 문제를 야기할 수 있으므로 반드시 피해야 하는 상황이다.
이러한 문제가 발생하지 않도록, OS는 다른 프로세스의 의도하지 않은 간섭으로부터 각 프로세스의 데이터 및 물리적 자원을 보호해야 하며 여기에 메모리, 파일 및 I/O 장치와 관련된 내용이 포함된다.
그리고 프로세스에서 수행하는 내용과 프로세스가 생성하는 결과는, 다른 동시 프로세스의 실행 속도와 무관, 즉 기능과 결과는 서로 독립적이어야 한다.
예방 할 수 있는 방법
이러한 race condition을 예방할 수 있는 방법으로 Mutex(뮤텍스)와 Semaphore(세마포어)가 있다.
Mutex(뮤텍스)
공유된 자원의 데이터를 여러 스레드가 접근하는 것을 막는 방법이다. 즉, Critical Section(각 프로세스에서 공유 데이터를 엑세스하는 프로그램 코드 부분)을 가진 쓰레드들의 Running time이 서로 겹치지 않게 각각 단독으로 실행되게 하는 기술이다. 다중 프로세스들이 공유 리소스에 대한 접근을 조율하기 위해 locking과 unloking을 사용하는데, 다시 말해서 상호배제를 함으로써 두 쓰레드가 동시에 사용할 수 없다는 뜻이다.
Semaphore(세마포어)
뮤텍스 보다 더 강력한 기능을 제공한다. 공유된 자원의 데이터를 여러 프로세스가 접근하는 것을 막는 것이다.
또한 세마포어는 리소스의 상태를 나타내는 간단한 카운터라고 할 수 있는데, 일반적으로 비교적 긴 시간을 확보하는 리소스에 대해 이용하게 되며, 운영체제의 리소스를 경쟁적으로 사용하는 다중 프로세스에서 행동을 조정하거나 동기화 시키는 기술이다. 다시 말해서 하나의 스레드만 들어가게 할 수도 있고 여러 개의 스레드가 들어가게 할 수 있다. 이것이 뮤텍스와의 차이이다.
세마포어의 구조는 한 개의 정수형 변수와 두 개의 동작으로 구성되어 있다. 두 개의 동작은 다음과 같이 불린다.
P = Proberen(test) = wait = acquire
V = Verhogen(increment) = signal = release
Proberen&Verhogen은 네덜란드어이고, 보통 OS 교과서에서는 wait & signal로 부른다.
acquire&release는 java.util.concurrent.Semaphore에 정의된 wait과 signal의 메서드명이다.
내용 비유 정리
해당 내용들을 공중 화장실 1개의 부스로 이해하기 쉽게 비유하자면,
공중 화장실 1개의 부스에 1명인데 화장실을 가고 싶어하는 사람이 여러명이라 서로 경쟁하려는 상황이 Race Condition 이고, 그 공간을 문을잠그고 혼자 사용하는 것이 Mutex 이다.
Mutex의 Critical Section(임계영역) 을 이용하여 locking 을 걸어 화장실 문을 잠가 다른 사람이 못 들어오게 할 수 있고, 볼 일을 다 본다면 unlocking 으로 다른 사람이 들어올 수 있게 할 수 있다.
Semaphore 는 중국 화장실(이미지를 찾아보면 한 공간에 여러 개의 변기가 있는 모습이다) 이라고 생각하면 된다. 몇 명이 들어갈 수 있는지 지켜보고 연속적으로 여러 명이 그 화장실에 동시에 들어갈 수 있는 것이다.
출처 및 참고: 강의 짱잘하시는 울 유니티 선생님 수업,
https://iredays.tistory.com/125
HyunZzang의 프로그래밍 공간 / 함께 공부해요!!
도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 부탁드립니다 :)