교착 상태 란 무엇입니까?


159

멀티 스레드 응용 프로그램을 작성할 때 가장 일반적인 문제 중 하나는 교착 상태입니다.

커뮤니티에 대한 나의 질문은 다음과 같습니다.

  1. 교착 상태 란 무엇입니까?

  2. 당신은 그들을 어떻게 감지합니까?

  3. 당신은 그들을 처리합니까?

  4. 그리고 마지막으로, 당신은 그것들이 발생하는 것을 어떻게 방지합니까?


답변:


207

잠금 여러 프로세스가 동시에 같은 리소스에 액세스하려고 할 때 발생합니다.

한 프로세스가 손실되고 다른 프로세스가 완료 될 때까지 기다려야합니다.

교착 상태가 대기 프로세스가 여전히 이전의 첫 번째 요구를 완료 할 수있는 다른 리소스에 들고 때 발생합니다.

예를 들면 다음과 같습니다.

자원 A와 자원 B는 프로세스 X와 프로세스 Y에서 사용됩니다.

  • X가 A를 사용하기 시작합니다.
  • X와 Y는 B를 사용하려고합니다.
  • Y '승리'하고 B를 먼저 얻는다
  • 이제 Y는 A를 사용해야합니다
  • A는 X를 잠그고 Y를 기다리고 있습니다.

교착 상태를 피하는 가장 좋은 방법은 프로세스가 이런 식으로 교차하지 않도록하는 것입니다. 가능한 한 많은 것을 잠글 필요가 없습니다.

데이터베이스에서 단일 트랜잭션으로 다른 테이블을 많이 변경하지 않도록 트리거를 피하고 가능한 한 낙관적 / 더러운 / 노락 읽기로 전환하십시오.


9
여기서는 OS 프로세스가 아닌 일반화로 프로세스를 사용하고 있습니다. 이들은 스레드 일 수 있지만 완전히 다른 응용 프로그램 또는 데이터베이스 연결 일 수도 있습니다. 패턴은 동일합니다.
Keith

1
안녕하세요,이 시나리오에서 스레드 A는 리소스 A를 잠그고 프로세스가 오래 걸립니다. 스레드 B가 리소스 A를 잠그기를 기다리고 있습니다. CPU 시간 사용량 : 20 %, 교착 상태 상황을 고려할 수 있습니까?
rickyProgrammer

2
@rickyProgrammer 아니요, 차이점은 약간 학문적이지만 정기적 인 잠금 대기입니다. 느리게 기다리는 B는 잠금이고, B를 기다리는 A는 교착 상태입니다.
Keith

교착 상태는 자원이 해제 될 때까지 대기중인 자원이있는 두 개의 프로세스 중 하나 이상입니다.
rickyProgrammer

2
@rickyProgrammer 순환 대기열 때문에 대기 시간에 관계없이 해제되지 않는 잠금 장치입니다.
Keith

126

범죄 영화의 교착 상태 상황에 대한 실제 (실제 아님) 예를 설명하겠습니다. 범죄자가 인질을 보유하고 있고 경찰이 범죄의 친구 인 인질을 보유하고 있다고 상상해보십시오. 이 경우 경찰이 친구를 보내지 않으면 범죄자가 인질을 보내지 않을 것입니다. 또한 경찰은 범죄자가 인질을 풀지 않는 한 범죄의 친구를 보내지 못하게 할 것입니다. 이것은 양측이 서로 첫 발을 내딛기 때문에 끝없는 신뢰할 수없는 상황입니다.

범죄 및 경찰 장면

여기에 이미지 설명을 입력하십시오

따라서 두 스레드에 두 개의 서로 다른 리소스가 필요하고 각 스레드에 다른 리소스가 필요한 경우 교착 상태입니다.

교착 상태에 대한 또 다른 높은 수준의 설명 : 상한 마음

당신은 소녀와 데이트를하고 논쟁 후 언젠가 양측이 서로에게 상처를 입히고 미안하고 부재중 전화를 기다리고 있습니다 . 이 상황에서 양측이 상대방 중 하나가 I-am- 미안 전화를 받는 경우에만 서로 통신을 원합니다 . 둘 다 통신을 시작하지 않고 수동 상태로 대기하지 않기 때문에 둘 다 상대방이 교착 상태 상황에서 통신을 시작하기를 기다립니다.


스레드가 다른 프로세스에 속해 있습니까? 같은 프로세스에 속하는 스레드도 교착 상태를 일으킬 수 있습니까?
lordvcs

1
@diabolicfreak 스레드가 동일한 프로세스에 속하는지 여부는 중요하지 않습니다.
Sam Malayek

2
실생활의 또 다른 예는 4 개의 자동차가 동시에 4 개의 방향으로 2 개의 동일한 도로를 건너는 것일 수 있습니다. 모든 사람은 오른쪽에서 차를 타야하므로 아무도 진행할 수 없습니다.
LoBo

35

교착 상태는 동시에 획득 할 수있는 둘 이상의 잠금이 있고 다른 순서로 잡은 경우에만 발생합니다.

교착 상태를 피하는 방법은 다음과 같습니다.

  • 잠금 장치를 피하십시오 (가능한 경우).
  • 하나 이상의 자물쇠를 피하십시오
  • 항상 같은 순서로 자물쇠를 가져 가십시오.

교착 상태를 방지하기위한 세 번째 포인트 (항상 동일한 순서로 잠금을 수행함)는 매우 중요하며 코딩 연습에서 잊기 쉽습니다.
Qiang Xu

20

교착 상태를 정의하기 위해 먼저 프로세스를 정의합니다.

프로세스 : 우리가 아는 것처럼 프로세스는 program실행 중일뿐입니다.

리소스 : 프로그램 프로세스를 실행하려면 몇 가지 리소스가 필요합니다. 리소스 범주에는 메모리, 프린터, CPU, 열린 파일, 테이프 드라이브, CD-ROM 등이 포함됩니다.

교착 상태 : 교착 상태는 둘 이상의 프로세스가 일부 자원을 보유하고 더 많은 자원을 확보하려고 할 때 상황 또는 조건이며 실행이 완료 될 때까지 자원을 해제 할 수 없습니다.

교착 상태 또는 상황

여기에 이미지 설명을 입력하십시오

위의 다이어그램에는 두 개의 프로세스 P1p2 가 있으며 두 개의 리소스 R1R2가 있습니다.

리소스 R1 은 프로세스 P1에 할당 되고 리소스 R2 는 프로세스 p2에 할당됩니다 . 프로세스 P1의 실행을 완료하려면 리소스 R2가 필요 하므로 P1R2를 요청 하지만 R2 는 이미 P2에 할당되어 있습니다.

같은 방법으로 프로세스 P2 가 실행을 완료하려면 R1이 필요 하지만 R1 은 이미 P1에 할당되어 있습니다.

두 프로세스 모두 실행을 완료 할 때까지는 리소스를 해제 할 수 없습니다. 그래서 둘 다 다른 자원을 기다리고 있으며 영원히 기다릴 것입니다. 이것이 DEADLOCK 조건입니다.

교착 상태가 발생하려면 네 가지 조건이 충족되어야합니다.

  1. 상호 배제 -각 자원은 현재 정확히 하나의 프로세스에 할당되었거나 사용 가능합니다. 두 프로세스가 동일한 리소스를 동시에 제어하거나 중요 섹션에있을 수는 없습니다.
  2. 보류 및 대기 -현재 자원을 보유하고있는 프로세스는 새 자원을 요청할 수 있습니다.
  3. 선점 없음 -프로세스가 자원을 보유하면 다른 프로세스 나 커널이이를 제거 할 수 없습니다.
  4. 순환 대기 -각 프로세스는 다른 프로세스가 보유한 자원을 얻기 위해 대기 중입니다.

이 모든 조건은 위 다이어그램에서 만족됩니다.


8

교착 상태는 스레드가 절대 발생하지 않는 것을 기다리고있을 때 발생합니다.

일반적으로 스레드가 이전 소유자가 릴리스하지 않은 뮤텍스 또는 세마포어를 기다리는 경우에 발생합니다.

또한 다음과 같이 두 개의 스레드와 두 개의 잠금이 관련된 상황이 발생할 때 자주 발생합니다.

Thread 1               Thread 2

Lock1->Lock();         Lock2->Lock();
WaitForLock2();        WaitForLock1();   <-- Oops!

일반적으로 예상되는 작업이 수행되지 않거나 응용 프로그램이 완전히 중단되기 때문에이를 감지합니다.


교착 상태는 스레드가 발생할 수없는 것을 기다리고있을 때 발생합니다.
Lorne의 후작

4

교착 상태 섹션 에서이 멋진 기사를 살펴볼 수 있습니다 . C #에 있지만 아이디어는 여전히 다른 플랫폼에서도 동일합니다. 나는 쉽게 읽을 수 있도록 여기에 인용한다.

교착 상태는 두 스레드가 각각 다른 스레드가 보유한 자원을 기다릴 때 발생하므로 어느 쪽도 진행할 수 없습니다. 이것을 설명하는 가장 쉬운 방법은 두 개의 자물쇠를 사용하는 것입니다.

object locker1 = new object();
object locker2 = new object();

new Thread (() => {
                    lock (locker1)
                    {
                      Thread.Sleep (1000);
                      lock (locker2);      // Deadlock
                    }
                  }).Start();
lock (locker2)
{
  Thread.Sleep (1000);
  lock (locker1);                          // Deadlock
}

4

교착 상태는 OS의 다중 처리 / 다중 프로그래밍 문제에서 공통적 인 문제입니다. 두 개의 프로세스 P1, P2 및 두 개의 공유 가능한 자원 R1, R2가 있으며 중요한 섹션에 두 자원 모두에 액세스해야한다고 가정하십시오.

초기에 OS는 R1을 프로세스 P1에 할당하고 R2를 프로세스 P2에 할당합니다. 두 프로세스가 동시에 실행 중이므로 코드 실행이 시작될 수 있지만 프로세스가 중요 섹션에 도달하면 문제가 발생합니다. 따라서 프로세스 R1은 프로세스 P2가 R2를 릴리스 할 때까지 대기하고 그 반대도 마찬가지입니다. 따라서 그들은 영원히 대기합니다 (DEADLOCK CONDITION).

작은 아날로그 ...

당신의 어머니 (OS),
당신 (P1),
당신의 형제 (P2),
사과 (R1),
칼 (R2),
비판 (칼로 사과 자르기).

당신의 어머니는 처음에 당신에게 형제에게 사과와 칼을줍니다.
둘 다 행복하고 놀고 있습니다 (코드 실행).
누구든지 어느 시점에서 사과 (중요 부분)를 자르기를 원합니다.
당신은 당신의 형제에게 사과를주고 싶지 않습니다.
당신의 형제는 당신에게 칼을주고 싶지 않습니다.
그래서 둘 다 오랫동안 아주 오래 기다릴 것입니다 :)


2

교착 상태는 두 스레드가 잠금을 요구할 때 발생하여 두 스레드 중 하나가 진행되지 못하게합니다. 이를 피하는 가장 좋은 방법은 신중한 개발입니다. 많은 임베디드 시스템은 워치 독 타이머 (시스템이 특정 시간 동안 중단 될 때마다 시스템을 재설정하는 타이머)를 사용하여 시스템을 보호합니다.


2

교착 상태는 각각 잠긴 자원을 보유하고 체인의 다음 요소가 보유한 자원을 잠그려고하는 스레드 또는 프로세스의 원형 체인이있을 때 발생합니다. 예를 들어, 잠금 A와 잠금 B를 각각 보유하고 다른 잠금을 획득하려고하는 두 스레드가 있습니다.


나는 당신에게 투표합니다. 대답은 프로세스 또는 스레드에 의해 혼동 교착 상태가 발생하기 때문에 위의 것보다 더 간결합니다. 어떤 사람은 프로세스를 말하고 어떤 사람은 스레드를 말합니다 :)
hainguyen

1

교착 상태 상황 을 이해하기위한 고전적이고 매우 간단한 프로그램 :-

public class Lazy {

    private static boolean initialized = false;

    static {
        Thread t = new Thread(new Runnable() {
            public void run() {
                initialized = true;
            }
        });

        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println(initialized);
    }
}

메인 스레드가 Lazy.main을 호출하면 Lazy 클래스가 초기화되었는지 확인하고 클래스 초기화를 시작합니다. 메인 스레드는 이제 initialized를 false로 설정하고 run 메소드가 initialized를 true로 설정하는 백그라운드 스레드를 작성하고 시작하며 백그라운드 스레드가 완료되기를 기다립니다.

이번에는 클래스가 현재 다른 스레드에 의해 초기화되고 있습니다. 이러한 상황에서 백그라운드 스레드 인 현재 스레드는 초기화가 완료 될 때까지 클래스 객체를 기다립니다. 불행하게도, 메인 스레드 인 초기화를 수행하는 스레드는 백그라운드 스레드가 완료되기를 기다리고 있습니다. 두 스레드가 서로 기다리고 있기 때문에 프로그램은 DEADLOCKED입니다.


0

교착 상태는 단일 프로세스 / 스레드가 조치를 실행할 수없는 시스템의 상태입니다. 다른 사람들이 언급했듯이 교착 상태는 일반적으로 각 프로세스 / 스레드가 다른 프로세스 (또는 동일한 프로세스) / 스레드에 의해 이미 잠겨있는 리소스에 대한 잠금을 획득하려는 상황의 결과입니다.

그들을 찾아 피하는 방법에는 여러 가지가 있습니다. 하나는 매우 열심히 생각하거나 많은 것을 시도하고 있습니다. 그러나 병렬 처리를 다루는 것은 매우 어렵고 대부분의 사람들은 문제를 완전히 피할 수 없습니다.

이러한 종류의 문제를 처리하는 데 진지한 경우 좀 더 공식적인 방법이 유용 할 수 있습니다. 내가 아는 가장 실용적인 방법은 프로세스 이론적 접근법을 사용하는 것입니다. 여기에서는 프로세스 언어 (예 : CCS, CSP, ACP, mCRL2, LOTOS)로 시스템을 모델링하고 사용 가능한 도구를 사용하여 교착 상태 (및 기타 속성도)를 (모델-) 확인합니다. 사용할 도구 세트의 예로는 FDR, mCRL2, CADP 및 Uppaal이 있습니다. 일부 용감한 영혼은 순전히 상징적 인 방법을 사용하여 자신의 시스템 교착 상태를 증명할 수도 있습니다 (정리 증명; Owicki-Gries 찾기).

그러나 이러한 공식적인 방법에는 일반적으로 약간의 노력이 필요합니다 (예 : 프로세스 이론의 기본 사항 배우기). 그러나 그것은 단순히 이러한 문제가 어렵다는 사실의 결과라고 생각합니다.


0

교착 상태는 다른 프로세스에서 요청한대로 사용 가능한 리소스 수가 적을 때 발생하는 상황입니다. 즉, 사용 가능한 리소스 수가 사용자가 요청한 것보다 적을 때 프로세스는 대기 상태가됩니다. 대기 시간이 길어지고 리소스 부족 문제를 확인할 기회가 없습니다. 이 상황을 교착 상태라고합니다. 실제로 교착 상태는 우리에게 중요한 문제이며 멀티 태스킹 운영 체제에서만 발생합니다. 모든 자원이 현재 실행중인 작업에만 존재하기 때문에 단일 작업 운영 체제에서는 교착 상태가 발생할 수 없습니다 ...


0

위의 설명은 훌륭합니다. 이것이 유용 할 수 있기를 바랍니다 : https://ora-data.blogspot.in/2017/04/deadlock-in-oracle.html

데이터베이스에서 세션 (예 : ora)이 다른 세션 (예 : 데이터)이 보유한 리소스를 원하지만 해당 세션 (데이터)도 첫 번째 세션 (오라)이 보유한 리소스를 원합니다. 세션이 두 개 이상있을 수도 있지만 아이디어는 동일합니다. 실제로 교착 상태는 일부 트랜잭션이 계속 작동하지 못하게합니다. 예를 들어, ORA-DATA가 잠금 A를 보유하고 잠금 B를 요청하고 SKU가 잠금 B를 보유하고 잠금 A를 요청한다고 가정하십시오.

감사,


0

교착 상태는 스레드가 다른 스레드가 완료되기를 기다리거나 그 반대 일 때 발생합니다.

피하는 방법?
-중첩 된 잠금
방지-불필요한 잠금 방지
-스레드 join () 사용

어떻게 감지합니까?
이 명령을 cmd에서 실행하십시오.

jcmd $PID Thread.print

참조 : geeksforgeeks


0

교착 상태는 잠금과 함께 발생하는 것이 아니라 가장 흔한 원인입니다. C ++에서는 std :: thread 객체에 대해 각 스레드 호출 join ()을 사용하여 두 개의 스레드로 잠금없이 교착 상태를 만들 수 있습니다.


0

잠금 기반 동시성 제어

공유 자원에 대한 액세스를 제어하기 위해 잠금을 사용하면 교착 상태가 발생하기 쉽고 트랜잭션 스케줄러만으로는 발생을 막을 수 없습니다.

예를 들어, 관계형 데이터베이스 시스템은 다양한 잠금을 사용하여 트랜잭션 ACID 특성 을 보장합니다 .

사용중인 관계형 데이터베이스 시스템에 관계없이 특정 테이블 레코드를 수정 (예 : UPDATE또는 DELETE) 할 때 항상 잠금이 획득됩니다 . 현재 실행중인 트랜잭션에 의해 수정 된 행을 잠그지 않으면 Atomicity가 손상 됩니다.

교착 상태 란 무엇입니까

이 기사 에서 설명했듯이 교착 상태는 다음 다이어그램과 같이 두 트랜잭션이 서로를 잠금 해제 할 때까지 대기하기 때문에 두 개의 동시 트랜잭션이 진행될 수 없을 때 교착 상태가 발생합니다.

여기에 이미지 설명을 입력하십시오

두 트랜잭션이 모두 잠금 획득 단계이므로 다음 트랜잭션을 획득하기 전에 어느 것도 잠금을 해제하지 않습니다.

교착 상태 상황에서 복구

잠금에 의존하는 동시성 제어 알고리즘을 사용하는 경우 항상 교착 상태 상황에서 실행될 위험이 있습니다. 교착 상태는 데이터베이스 시스템뿐만 아니라 모든 동시성 환경에서도 발생할 수 있습니다.

예를 들어, 멀티 스레딩 프로그램은 두 개 이상의 스레드가 이전에 획득 한 잠금을 대기하여 스레드가 진행될 수 없도록 교착 상태를 일으킬 수 있습니다. Java 애플리케이션에서 이러한 상황이 발생하면 JVM은 스레드가 강제로 실행을 중지하고 잠금을 해제하도록 할 수 없습니다.

Thread클래스가 stop메소드를 노출 하더라도 해당 메소드는 스레드가 중지 된 후 오브젝트가 불일치 상태로 남을 수 있으므로 Java 1.1 이후 더 이상 사용되지 않습니다. 대신, Java는 interrupt인터럽트를받는 스레드가 단순히 인터럽트를 무시하고 실행을 계속할 수있는 힌트 역할을 하는 메소드를 정의합니다 .

이러한 이유로 Java 응용 프로그램은 교착 상태 상황에서 복구 할 수 없으며 교착 상태가 발생하지 않도록 잠금 획득 요청을 주문하는 것은 응용 프로그램 개발자의 책임입니다.

그러나 데이터베이스 시스템은 특정 트랜잭션이 추가로 획득하려는 다른 잠금을 예측할 수 없으므로 주어진 잠금 획득 순서를 시행 할 수 없습니다. 잠금 순서를 유지하는 것은 데이터 액세스 계층의 책임이되며 데이터베이스는 교착 상태 상황을 복구하는 데 도움을 줄 수 있습니다.

데이터베이스 엔진은 교착 상태로 인한 잠금 대기주기에 대한 현재 충돌 그래프를 스캔하는 별도의 프로세스를 실행합니다. 주기가 감지되면 데이터베이스 엔진이 하나의 트랜잭션을 선택하고 중단하여 잠금이 해제되어 다른 트랜잭션이 진행될 수 있습니다.

JVM과 달리 데이터베이스 트랜잭션은 원자 단위 작업으로 설계되었습니다. 따라서 롤백은 데이터베이스를 일관된 상태로 둡니다.

이 주제에 대한 자세한 내용은 이 기사 도 확인하십시오 .


-2

본질적으로 Mutex는 공유 리소스에 대한 보호 된 액세스를 제공하는 잠금입니다. Linux에서 스레드 뮤텍스 데이터 유형은 pthread_mutex_t입니다. 사용하기 전에 초기화하십시오.

공유 리소스에 액세스하려면 뮤텍스를 잠 가야합니다. 뮤텍스가 이미 잠금 상태 인 경우 호출은 뮤텍스가 잠금 해제 될 때까지 스레드를 차단합니다. 공유 리소스 방문이 완료되면 잠금 해제해야합니다.

전반적으로 몇 가지 기록되지 않은 기본 원칙이 있습니다.

  • 공유 자원을 사용하기 전에 잠금을 확보하십시오.

  • 잠금 장치를 최대한 짧게 유지하십시오.

  • 스레드가 오류를 반환하면 잠금을 해제하십시오.


3
교착 상태가 아니라 잠금을 설명합니다.
Lorne의 후작
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.