스레드 동기화 문제


멀티프로세싱이나 멀티스레딩을 개발할 때 프로세스나 스레드들의 상태 제어 처리하는 부분에 까다로운 점이 많습니다.

스레드의 개수가 많아질수록 더욱 정교한 처리가 필요하고 스레드들이 동시에 실행되기 때문에 문제의 원인을 파악하는 것도 쉽지 않습니다. 따라서 기본적인 개념 이해와 프로그램이 동작하는 방식에 깊은 이해가 필요합니다.

이번 글에서는 스레드 동기화의 문제가 발생할 수 있는 것들을 개념적으로 살펴보겠습니다.

스레드 동기화 문제

레이스 컨디션(Race Condition)

race condition

레이스 컨디션이란 두 개 이상의 프로세스 혹은 스레드가 공유 자원을 서로 사용하려고 경합(Race)하는 현상을 말합니다. 동시에 공유 자원에 접근할 수 있으면 자원의 일관성을 해치는 결과가 발생할 수 있습니다. 그래서 동시에 공유 자원에 접근할 수 없도록 상호 배제(Mutual Exclusion) 조건을 만들어 놓는데, 여러 스레드가 하나의 스레드만이 차지할 수 있는 락을 획득하기 위해 경합(Race)한다고 해서 붙여진 이름으로 보입니다. 하지만, 상호 배제를 한다고 하여도 다음과 같은 문제가 발생할 수 있습니다.

교착 상태(Deadlock)

교착 상태공유 자원에 대한 요구가 엉켜서 자원 관리를 잘못하여 프로세스나 스레드가 자원의 락을 획득하기 위해 무한 대기 하는 것을 말합니다.

교착 상태가 발생할 수 있는 조건은 다음과 같습니다.

  • 상호 배제(Mutual Exclusion)

    레이스 컨디션의 문제를 해결하기 위해 두 개 이상의 프로세스 혹은 스레드가 동시에 한 공유 자원에 접근할 수 없도록 하여 한 자원에 한 스레드만 접근할 수 있게 하는 것상호 배제라고 합니다.

    자원에 대한 배타적 통제권, 즉 해당 자원을 오직 나 자신만 쓰겠다고 하는 상황을 말합니다.

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

  • 점유 상태로 대기(Hold and Wait)

    hold and wait

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

    발생할 수 있는 상황이 여러 개의 자원을 동시에 써야하는 경우, 락을 획득한 자원에 대한 처리는 끝났는데 남은 자원의 락을 다른 스레드가 가지고 해제를 하지 않아서 무한정 대기하고 있을 수 있습니다. 게다가 자신이 점유하고 있는 락도 해제를 해줘야 그 락을 획득하기 위해 기다리고 있는 다른 스레드들고 자원에 접근하여 처리를 할 수 있을텐데, 락을 획득할 수 없으니 무한정 대기할 수 밖에 없는 상황이 발생할 수 있습니다.

  • 선점 불가(No Preemption)

    다른 프로세스나 스레드가 자원을 선점하고 있어서 자원을 뺏어올 방법이 없는 것선점 불가라고 합니다.

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

  • 순환성 대기(Circular Wait)

    circular wait

    프로세스가 어느 자원을 점유하고 있고 다른 자원을 요청하여 대기하고 있는데 순환적으로 이러한 구조를 갖고 있는 것순환성 대기라고 합니다.

    즉, 점유 상태로 대기가 순환적으로 발생한 상황으로 볼 수 있는데 락을 해제하고 락을 획득하는게 순차적으로 잘 돌아가면 좋겠지만 어느 순간 모든 프로세스가 락을 획득하려고 대기하여 모든 프로세스가 무한 대기에 놓인 상황이 발생할 수 있습니다.

기아 상태(Starvation)

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

데드락은 공유 자원에 대한 요구가 엉켜서 모든 프로세스가 락을 획득하기 위해 기다리고 있는 것이지만 기아상태는 우선순위가 낮은 스레드가 공유 자원에 접근하기 위해 대기하고 있는데 자꾸 우선순위가 높은 스레드가 접근을 해서 자꾸 밀리게 되어 아무런 처리를 못하게 됩니다.

만약 공유 자원이 1개, 스레드가 4개가 있고 3개의 스레드는 우선순위가 높고 1개의 스레드는 우선순위가 낮을 때, 우선순위가 높은 스레드들이 번갈아가며 모든 시간을 공유 자원에 접근한다면 우선순위가 낮은 스레드는 자원에 접근하기 위해 대기하고 있지만 계속 우선순위가 높은 스레드가 다시 접근하려고 한다면 양보를 해야합니다. 그래서 우선순위가 낮은 스레드는 자원에 접근하지 못하고 쭉 대기만 해야하는 상황이 되어 아무 일도 못하게 됩니다.

라이브락(Livelock)

livelock

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

데드락을 피하기 위해 프로세스가 락을 획득하지 못할 경우 대기 상태로 빠지지 않도록 하고 자신이 획득한 락을 해제시켜서 다른 프로세스가 자신이 점유하고 있던 자원에 접근할 수 있도록 처리하고 다시 시작을 합니다. 다른 프로세스와 이 과정이 순환적으로 이러나게 되면 이 두 프로세스는 아무것도 하지 못하는 상황이 발생하여 결국 데드락과 같은 결과를 가져옵니다. 위 그림에서 프로세스 1과 2가 동시에 실행되어 1~3번의 과정이 무한 반복하게 되면 라이브락의 결과를 가져옵니다.

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기