033 Deadlock

강의 메모 - Deadlock - 교착상태 - 1,2 #

개요 #

  • DeadLock(교착상태) 이란 프로세스나 스레드들이 서로가 소유하고 있는 자원을 기다리며 무한히 대기하고 있는 상태를 말한다
  • 교착상태에서는 아무런 진전도 이루어지지 않아 작업이 진행되지 않는 문제가 발생한다
  • DeadLock 은 동일한 환경과 코드에서 발생할 수도 있고 발생하지 않을 수도 있다
    • 완전한 해결은 없고, ‘예방’과 ‘최소화’하는 느낌 - 예측이 어려운 상황

데드락 발생 조건 #

데드락은 다음의 네 가지 필요 조건을 동시에 만족할 때 발생한다. 한 가지라도 만족하지 않으면 데드락이 발생하지 않는다

  • 상호 배제(Mutual Exclusion)

    • 자원은 한 번에 하나의 스레드만 사용할 수 있다
    • ex) 철학자는 한번에 하나의 젓가락을 사용할 수 있으므로, 상호 배제를 구현하여 젓가락을 동시에 두 명 이상의 철학자가 사용하지 못하도록 한다
  • 점유 대기(Hold and Wait)

    • 스레드가 최소한 하나의 자원을 보유한 상태에서 다른 자원을 기다리고 있다
    • ex) 철학자들은 젓가락을 기다리는 상태에서 무한히 대기할 수 있으며, 다른 철학자가 젓가락을 반납하기를 기다릴 수 있다
  • 비선점(No Preemption)

    • 자원을 할당 받은 스레드가 자원을 스스로 반납하기 전까지 자원을 강제로 빼앗을 수 없다
      • 스레드가 wait()에 스스로 빠지게되거나, 작업을 완료하는거 외에 lock을 해제할 수 없다
      • 선점 : 쓰레드가 여러개 있을때 CPU가 쓰레드들은 컨텍스트 스위칭하면서 작업을 할당하는데 정해진 시간동안만 수행시키고 계속 바꿔가는것
    • ex) 철학자들은 젓가락을 사용하는 동안 다른 철학자에 의해 젓가락을 강제로 반납될 수 없으며, 젓가락은 해당 철학자에 의해 반납될 때까지 보유된다
  • 순환 대기(Circular Wait)

    • 각 스레드는 순환적으로 다음 스레드가 요구하는 자원을 가지고 있어 사이클이 형성된다
    • ex) 각 철학자는 서로 다른 두 개의 젓가락을 사용해야 하므로 순환적으로 다음 철학자가 요구하는 젓가락을 가지고 있을 수 있어 사이클이 형성된다

데드락 사례 #

(1) 락 순서에 의한 데드락 (보편적) img.png

  • lock1, lock2
    • 다른 쓰레드가 보유한 lock의 해제를 기다리는 상황
    • 현재 본인이 가지고있는 lock을 해제를 기다리던 쓰레드가 또 기다리는 상황

(2) 동적인 락 순서에 의한 데드락 img_1.png

(3) 객체 간의 데드락 img_2.png

데드락 방지와 원인 추적 #

  • 데드락 방지는 데드락 발생 조건인 네 가지 중에서 최소한 1가지를 방지함으로서 네 가지를 모두 만족하지 않게 하는 기법이다

  • 일단 데드락이 발생하면 어플리케이션 단에서 데드락을 해소하는 것은 어렵고 서버를 재 기동하거나 종료하는 것 밖에 현실적으로 다른 해결책은 없다

  • 한번에 하나 이상의 락을 사용하지 않는다

    • 데드락은 스레드가 락을 중첩으로 제어하면서 발생하는 경우가 많기 때문에 가능한 한 스레드가 두 개 이상의 락을 제어하는 상황을 만들지 않도록 하는 것이 좋다
  • 락의 순서를 잘 조정한다

    • 불가피하게 여러 개의 락을 사용해야 한다면 락의 점유 순서를 일정한 순서로 정해주도록 함으로써 데드락이 발생할 수 있는 조건 중 하나인 순환 대기를 방지하도록 한다
  • 락 타임아웃을 건다

    • 락을 요청할 때 일정 시간 이내에 락을 얻지 못하면 다른 작업을 수행하도록 타임아웃을 설정한다.
    • 락 획득에 타임아웃 오류가 나면 오래 기다리지 않고 제어권이 다시 돌아오기 때문에 현재 소유한 락을 해제하고 잠시 기다리다가 데드락 상황이 지나가면 다시 정상으로 동작할 수 있다
  • 메서드는 오픈 호출 형태로 구현한다

    • 락을 전혀 확보하지 않은 상태에서 메서드를 호출하는 것을 오픈 호출이라고 하며 락을 전체 메서드에 적용하지 않고 락이 필요한 임계영역만 보호하도록 한다
    • 여러 개의 락을 호출하더라도 동시에 락을 점유하는 것이 아닌 순차적으로 락을 획득하고 해제하는 방식으로 메서드를 호출하도록 한다
  • 스레드 덤프를 활용한다

    • 스레드 덤프에는 실행중인 스레드의 모든 스택 트레이스가 담겨져 있고 락과 관련된 정보도 포함되어 있기 때문에 이를 활용해서 어디에서, 어떤 스레드가 , 어느 시점에 , 왜 데드락이 발생했는지 원인을 추척 및 분석하고 해결방안을 모색할 수 있다

데드락 방지 #

(1) 락 순서를 조절한다 img_3.png

(2) 락에 타임아웃을 건다 img_4.png

(3) 메서드 오픈 호출 img_5.png

그 외 활동성 문제 #

  • 기아상태(Starvation)

    • 멀티스레드 환경에서 한 스레드가 자원을 계속해서 얻지 못하여 영원히 대기하는 상태를 말한다
    • 다른 스레드들이 우선적으로 자원을 점유하거나 실행되어 해당 스레드가 자원을 얻지 못하게 되면 기아 상태가 발생한다
    • 기아 상태를 해결하기 위해서는 우선순위를 기반으로 한 스케줄링이 아니라 공정성을 고려하여 모든 스레드가 공평하게 실행될 수 있도록 우선순위를 조정하는 등의 설계가 뒷받침 되어야 한다
  • 라이브락(Livelock)

    • 라이브락은 데드락과 비슷한 상태로, 여러 스레드가 서로의 자원을 기다리면서 진행이 지연되는 상태를 말한다
    • 라이브락은 데드락과는 다르게 작업이 멈추지 않고 계속해서 진행되지만, 실질적인 작업이 진행되지 않거나 진행이 제대로 이루어지지 않는 상태를 의미한다
    • 라이브락 상태에서는 스레드가 서로의 자원을 기다리기 때문에 작업이 충분히 느려질 수 있으며, 서로가 양보하는 동작이 반복되면서 진행이 지연되는 상태가 발생한다

img_6.png