레이스 컨디션 그게 뭐야?

maketheworldwise·2022년 1월 10일
1


이 글의 목적?

이전 포스팅과 이어서 스레드에서 발생할 수 있는 문제를 정리해보고자 한다.

레이스 컨디션

개념부터 살펴보면 레이스 컨디션은 두 개 이상의 프로세스 혹은 스레드가 공유 자원을 서로 사용하려고 경합(Race)하는 현상을 의미한다.

그렇다면 어떤 문제가 발생할 수 있을까? 답은 간단하다. 멀티 스레드 환경에서는 프로세스 내의 모든 자원을 공유할 수 있다는 점에서 동기화 문제가 발생한다.

예를 들어 두 개의 스레드를 이용하여 a라는 변수에 11이라는 값을 저장하는 것이 목적이라고 하자.

1. 값이 0이 저장된 변수 a
2. 스레드 A, B
3. 스레드 A는 변수 a를 읽어옴
4. 스레드 B는 변수 a를 읽어옴
5. 스레드 A는 변수 a에 값을 10 더한 값을 저장
6. 스레드 B는 변수 a에 값을 1을 더한 값을 저장

이 과정의 결과는 11이 아닌 1이 들어가게 된다. 이처럼 동시에 공유 자원에 접근함으로서 자원의 일관성을 해치는 결과가 발생하는 것을 레이스 컨디션이라고 한다. 상호 배제 조건을 만들어 동시에 공유 자원에 접근할 수 없도록 할 수도 있으나, 이 조건으로 인해 다른 문제가 발생할 수 있다.

교착 상태

교착 상태(DeadLock)는 공유 자원에 대한 요구가 엉켜서 자원 관리를 잘못하여 프로세스나 스레드가 자원의 락을 획득하기 위해 무한 대기하는 것을 의미한다. 교착 상태가 발생할 수 있는 조건을 살펴보자.

1. 상호 배제

레이스 컨디션의 문제를 해결하고자 상호 배제 조건을 두어 동시에 공유 자원에 접근할 수 없도록 하여 한 자원에 한 스레드만 접근 할 수 있게 하는 것을 의미한다.

스레드가 자원을 독점적으로 사용하고 있어 다른 스레드가 자원에 접근하려고 락을 획득하기 위해 무한 대기할 수 있는 상황이 발생할 수 있다.

2. 점유 상태로 대기

공유 자원에 락을 획득하여 점유하고 있는 상태인데 다른 자원의 락을 획득하기 위해 대기하고 있는 상황을 의미한다.

조금 더 이해하기 쉽게 풀어서 말해본다면, 발생할 수 있는 상황이 여러 개의 자원을 동시에 써야하는 경우 락을 획득한 자원에 대한 처리는 끝났는데 남은 자원의 락을 다른 스레드가 가지고 해제를 하지 않아 무한정 대기하는 상태다.

또한 자신이 점유하고 있는 락도 해제를 해주어야 그 락을 획득하기 위해 대기하고 있는 다른 스레드들도 자원에 접근하여 처리를 할 수 있는데 락을 획득할 수 없어 다른 스레드 마저 무한정 대기할 수 밖에 없는 상황이 발생한다.

출처: https://cheetile.tistory.com/entry/OS-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%8F%99%EA%B8%B0%ED%99%94-%EB%AC%B8%EC%A0%9C-Race-Condition-Deadlock-Starvation-Livelock

3. 선점 불가

다른 스레드가 자원을 선점하고 있어서 자원을 뺏어올 방법이 없는 것을 의미한다. 만일 어느 스레드가 공유 자원의 락을 획득하여 선점하고 있다면 그 공유 자원에 접근해야 하는 다른 스레드들은 아무리 잠깐 처리하면 끝나는 상황이라도 락을 빼앗을 방법이 없기 때문에 무한 대기할 상황이 발생할 수 있다.

개인적으로 스레드가 자원을 독점하고 있다는 점에서 발생한 문제이기에 상호 배제와 비선점에서는 크게 차이가 있다고 생각하지 않는다. 굳이 나눈다면 상호 배제와 비선점에는 "자원을 선점하고 있는 스레드"를 기준으로 삼거나 "자원을 선점하고 있지 않은 스레드"를 기준으로 바라보는 관점에서 차이가 있는 것 같다. 🧐

4. 순환성 대기

프로세스가 어느 자원을 점유하고 있고 다른 자원을 요청하여 대기하고 있는데 순환적인 구조를 가지는 경우를 순환성 대기라고 한다.

출처: https://cheetile.tistory.com/entry/OS-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%8F%99%EA%B8%B0%ED%99%94-%EB%AC%B8%EC%A0%9C-Race-Condition-Deadlock-Starvation-Livelock

기아 상태

기아 상태는 스레드들에게 우선 순위를 부여하여 공유 자원에 접근할 때 우선 순위가 낮은 스레드가 소외되어 아무일도 하지 못하는 상태를 의미한다.

교착 상태는 공유 자원에 대한 요구가 엉켜서 발생한 문제라면, 기아 상태는 우선 순위가 낮은 스레드가 공유 자원에 접근하기 위해 대기하고 있는데 우선 순위가 높은 스레드가 접근을 하여 뒤로 밀려 아무런 처리를 못하게 되는 상태다.

라이브락

라이브락은 교착 상태와 비슷한 결과를 가져오지만 다른 과정을 통해 발생하는 문제다. 교착 상태는 공유 자원의 락을 획득하기 위해 모든 스레드가 무한 대기한다면, 라이브락은 스레드들이 동시에 실행되면서 락의 해제와 획득을 반복적으로 하면서 정상적으로 동작하는 것 처럼 보이나 사실상 아무것도 못하고 무한 동작중인 상황을 말한다.

교착 상태를 피하기 위해 스레드가 락을 획득하지 못할 경우 대기 상태로 빠지지 않도록 자신이 획득한 락을 해제시켜서 다른 프로세스가 자신이 점유하고 있던 자원에 접근할 수 있도록 처리하고 다시 시작을 한다. 이 과정이 다른 스레드에서도 발생한다면, 두 스레드는 아무것도 하지 못하는 상황이 발생하게 되어 교착 상태와 동일한 결과를 가져오게 된다.

출처: https://cheetile.tistory.com/entry/OS-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%8F%99%EA%B8%B0%ED%99%94-%EB%AC%B8%EC%A0%9C-Race-Condition-Deadlock-Starvation-Livelock

임계 영역

레이스 컨디션을 찾아보면서 함께 나오는 임계 영역에 대해서 알아보자. 🥲

임계 영역(Critical Section)은 여러 개의 스레드가 수행되는 시스템에서 각 스레드들이 공유하는 데이터를 변경하는 코드 영역이다.

그리고 중요한 점은 임계 영역을 통해 레이스 컨디션을 예방할 수 있다는 것이다. 단, 3가지의 조건을 충족해야한다.

1. 상호 배제

교착 상태의 상호 배제와 동일한 개념이다. 한 스레드가 임계 구역에서 수행중인 상태에서 다른 스레드는 접근하지 못하는 것을 의미한다. 뮤텍스와 세마포어와 같은 락 메커니즘을 통해 구현할 수 있다.

2. 진행

대기하고 있는 스레드중 누가 먼저 들어갈 것인가에 대한 결정이 유효 시간 내에 일어나야 한다. 임계 영역에 어떤 스레드도 없다면 기다리고 있는 스레드는 무조건 임계 영역에 진입가능해야 한다.

3. 제한된 대기

임계 구역으로 진입하기 위해 대기하는 모든 스레드는 유한 시간 이내에 해당 임계 구역으로 진입할 수 있어야 한다. 기아 상태를 피하기 위해 한번 임계 영역에 들어간 스레드가 다시 임계 영역에 들어갈 때는 제한을 두어야 한다.

뮤텍스

내가 읽은 레퍼런스에서는 화장실이 하나밖에 없는 식당으로 비유를 했다.

1. 화장실이 하나밖에 없는 식당
2. A는 화장실을 가기 위해 카운터에서 열쇠를 받고 화장실을 사용한다.
3. B는 화장실을 가기 위해 카운터에서 열쇠를 찾음 => 대기
4. C는 화장실을 가기 위해 카운터에서 열쇠를 찾음 => 대기
5. A가 화장실을 나와 카운터에 열쇠를 되돌려 놓음 => 해제
6. B는 화장실 열쇠를 가지고 화장실을 사용
7. ...(반복)

화장실을 이용하는 사람을 스레드, 화장실은 공유 자원, 화장실 열쇠는 공유 자원에 접근하기 위해 필요한 특정 오브젝트를 의미한다. 즉, 뮤텍스는 열쇠에 해당하는 특정 오브젝트가 있으며 이 오브젝트를 소유한 스레드만이 공유 자원에 접근이 가능하다.

다시 정리해보자. 🤩 뮤텍스는 자원에 대한 접근을 동기화하기 위해 사용되는 상호 배제 기술이다. 뮤텍스는 락 메커니즘으로 오직 하나의 스레드만이 동일한 시점에 뮤텍스를 얻어 임계 영역에 접근할 수 있다. 그리고 오직 이 스레드만이 임계 영역에서 나갈 때 뮤텍스를 해제할 수 있다.

세마포어

내가 읽은 레퍼런스에서는 화장실이 여러 개인 식당으로 비유를 했다. 그리고 화장실 입구에는 현재 몇 개의 화장실이 비어있는지 보여주는 전광판이 있다고 가정했다.

1. 화장실이 2 개 있는 식당
2. A는 빈 칸의 수를 확인하고 1개 이상일 경우 빈 칸의 개수를 줄이고 화장실로 입장
3. B는 빈 칸의 수를 확인하고 1개 이상일 경우 빈 칸의 개수를 줄이고 화장실로 입장
3. C는 빈 칸의 수를 확인히고 빈 칸의 개수가 1개 이상일 때 까지 대기
4. A는 화장실을 나오면서 빈 칸의 개수를 늘림
5. C는 빈 칸의 수를 확인하고 화장실로 입장
6. ...(반복)

세마포어도 뮤텍스와 동일하게 공통으로 관리하는 하나의 값을 이용해 상호배제를 달성한다. 뮤텍스와 동일하게 화장실을 이용하는 사람을 스레드, 화장실은 공유 자원, 빈 칸의 개수는 현재 공유 자원에서 접근할 수 있는 스레드의 개수를 의미한다.

세마포어는 Signaling 메커니즘으로, 락을 걸지 않은 스레드도 Signal을 보내 락을 해제할 수 있다는 점에서 뮤텍스와 다르다.

(세마포어는 크게 Counting과 Binary 세마포어로 나뉜다. 세마포어의 기본적인 개념만 잡고 뮤텍스와 다르다는 점만 숙지하고 넘어가자! 😵‍💫)

정리해보자 👏

  • 레이스 컨디션 은 자원을 공유할 때 발생하는 경쟁 상태이며, 자원의 동기화에서 문제가 발생한다. 상호 배제 조건을 통해서 동시에 공유 자원에 접근할 수 없도록 할 수 있으나 교착 상태에 빠질 수 있다.

  • 교착 상태 는 공유 자원에 대한 요구가 엉켜 자원의 락을 획득하기 위해 무한 대기하는 상태다. 교착 상태는 상호 배제, 점유 상태로 대기, 선점 불가(비선점), 순환성 대기의 조건으로 발생할 수 있다.

  • 기아 상태 는 우선 순위가 가장 낮은 스레드가 끊임없이 뒤로 밀려 무한정 대기 상태를 의미한다.

  • 라이브락 은 스레드가 동시에 실행되면서 락의 해제와 획득을 반복적으로 하면서 정상적으로 동작하는 것 처럼 보이나 아무것도 하지 않는 상태를 의미한다.

  • 임계 영역 은 여러 개의 스레드가 수행되는 시스템에서 각 스레드들이 공유하는 데이터를 변경하는 코드 영역이다. 상호 배제, 진행, 제한된 대기 조건을 만족해야 임계 영역을 통해 레이스 컨디션을 예방할 수 있다.

  • 뮤텍스와 세마포어 는 자원에 대한 접근을 동기화하기 위해 사용되는 상호 배제 기술이다.

이 글의 레퍼런스

profile
세상을 현명하게 이끌어갈 나의 성장 일기 📓

0개의 댓글