문제

다중 스레드 애플리케이션을 작성할 때 경험하는 가장 일반적인 문제 중 하나는 교착 상태입니다.

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

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

  2. 어떻게 감지합니까?

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

  4. 마지막으로 이러한 일이 발생하지 않도록 하려면 어떻게 해야 합니까?

도움이 되었습니까?

해결책

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

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

이중 자물쇠 대기 중인 프로세스가 완료되기 전에 첫 번째 필요한 다른 리소스를 계속 보유하고 있을 때 발생합니다.

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

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

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

교착 상태를 피하는 가장 좋은 방법은 이러한 방식으로 프로세스가 교차되는 것을 방지하는 것입니다.가능한 한 모든 것을 잠글 필요성을 줄이세요.

데이터베이스에서는 단일 트랜잭션에서 다른 테이블을 많이 변경하지 말고, 트리거를 피하고 가능한 한 낙관적/더티/잠금 없음 읽기로 전환하세요.

다른 팁

범죄 영화에 나오는 교착 상태 상황에 대한 실제(실제로는 실제가 아닌) 예를 설명하겠습니다.범죄자가 인질을 잡고 있고, 이에 맞서 경찰도 범죄자의 친구를 인질로 잡고 있다고 상상해보세요.이 경우, 경찰이 친구를 놓아주지 않으면 범죄자는 인질을 놓아주지 않을 것입니다.또한 경찰은 범죄자가 인질을 석방하지 않는 한 범죄자의 친구를 놓아주지 않을 것입니다.양측이 서로 첫걸음을 내딛고 있기 때문에 끝도 없이 신뢰할 수 없는 상황이다.

범죄 및 경찰 현장

enter image description here

간단히 말해서, 두 스레드가 서로 다른 두 리소스를 필요로 하고 각 스레드가 다른 스레드가 필요로 하는 리소스 잠금을 갖고 있는 경우 교착 상태가 발생합니다.

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

당신은 여자와 데이트를 하고 있는데, 어느 날 말다툼을 한 후 양측은 서로에게 상처를 받고 만남을 기다리고 있습니다. 미안하고 보고 싶었어 부르다.이 상황에서 양측은 한쪽이 통신을 수신하는 경우에만 서로 통신하기를 원합니다. 미안해요 상대방에게서 전화를 겁니다.둘 중 어느 쪽도 통신을 시작하지 않고 수동적 상태로 기다리지 않기 때문에 둘 다 다른 쪽이 통신을 시작하기를 기다리다가 결국 교착 상태에 빠지게 됩니다.

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

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

  • 잠금 장치를 사용하지 마십시오(가능한 경우).
  • 하나 이상의 잠금을 피하십시오
  • 항상 같은 순서로 잠금을 수행하십시오.

교착 상태를 정의하려면 먼저 프로세스를 정의합니다.

프로세스 : 우리가 알고 있듯이 프로세스는 단지 program 실행 중.

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

이중 자물쇠 : 교착 상태는 두 개 이상의 프로세스가 일부 리소스를 보유하고 더 많은 리소스를 얻으려고 시도하며 실행이 완료될 때까지 리소스를 해제할 수 없는 상황 또는 조건입니다.

교착 상태 또는 상황

enter image description here

위 다이어그램에는 두 가지 프로세스가 있습니다. P1 그리고 p2 두 가지 리소스가 있습니다. R1 그리고 R2.

자원 R1 프로세스에 할당됩니다. P1 및 자원 R2 프로세스에 할당됩니다. p2.프로세스 실행을 완료하려면 P1 자원이 필요하다 R2, 그래서 P1 요청하다 R2, 하지만 R2 이미 할당되어 있습니다. P2.

같은 방식으로 프로세스 P2 실행 요구를 완료하기 위해 R1, 하지만 R1 이미 할당되어 있습니다. P1.

두 프로세스 모두 실행이 완료될 때까지 리소스를 해제할 수 없습니다.따라서 둘 다 다른 리소스를 기다리고 있으며 영원히 기다릴 것입니다.그래서 이것은 이중 자물쇠 상태.

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

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

위의 다이어그램에서는 이러한 모든 조건이 충족됩니다.

교착 상태는 스레드가 결코 발생하지 않는 일을 기다릴 때 발생합니다.

일반적으로 스레드가 이전 소유자가 해제한 적이 없는 뮤텍스나 세마포어를 기다리고 있을 때 발생합니다.

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

Thread 1               Thread 2

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

일반적으로 예상했던 일이 발생하지 않거나 애플리케이션이 완전히 중단되기 때문에 이를 감지합니다.

이것을 살펴볼 수 있습니다. 멋진 기사, 섹션 아래 이중 자물쇠.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
}

교착 상태는 OS의 다중 처리/다중 프로그래밍 문제에서 흔히 발생하는 문제입니다.두 개의 프로세스 P1, P2와 전역적으로 공유 가능한 두 개의 리소스 R1, R2가 있고 중요한 섹션에서는 두 리소스에 모두 액세스해야 한다고 가정해 보겠습니다.

처음에 OS는 R1에 P1을 처리하도록 할당하고 R2에 P2를 처리하도록 할당합니다.두 프로세스가 동시에 실행 중이므로 코드 실행을 시작할 수 있지만 프로세스가 임계 섹션에 도달하면 문제가 발생합니다.따라서 프로세스 R1은 프로세스 P2가 R2를 릴리스할 때까지 기다리며 그 반대의 경우도 마찬가지입니다.따라서 그들은 영원히 기다릴 것입니다(교착 상태 조건).

작은 비유...

당신의 어머니(OS),
당신(P1),
네 동생(P2),
애플(R1),
칼(R2),
중요한 부분(칼로 사과 자르기).

어머니는 처음에 형에게 사과와 칼을 줍니다.
둘 다 행복하고 놀고 있습니다(코드 실행 중).
여러분 중 누구라도 어느 시점에서 사과(중요한 부분)를 자르고 싶어할 것입니다.
당신은 사과를 동생에게 주고 싶지 않습니다.
당신의 형은 당신에게 칼을 주고 싶어하지 않습니다.
그래서 두 분 모두 아주 오랫동안 기다리실 거에요 :)

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

교착 상태는 두 스레드가 둘 중 하나의 진행을 방해하는 잠금을 획득할 때 발생합니다.이를 피하는 가장 좋은 방법은 신중한 개발입니다.많은 임베디드 시스템은 감시 타이머(특정 시간 동안 시스템이 정지될 때마다 시스템을 재설정하는 타이머)를 사용하여 이를 방지합니다.

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

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

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

그러나 이러한 형식적 방법에는 일반적으로 약간의 노력이 필요합니다(예:프로세스 이론의 기초를 학습합니다.)그러나 나는 이것이 단지 이러한 문제가 어렵다는 사실의 결과라고 생각합니다.

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

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

데이터베이스에서 세션(예:ora)는 다른 세션에서 보유하고 있는 리소스를 원합니다(예:데이터), 그러나 해당 세션(데이터)은 첫 번째 세션(ora)이 보유하는 리소스도 원합니다.2개 이상의 세션이 포함될 수도 있지만 아이디어는 동일합니다.실제로 교착 상태는 일부 트랜잭션이 계속 작동하는 것을 방지합니다.예를 들어:Ora-Data가 잠금 A를 보유하고 요청을 요청하고 Sku는 잠금 B를 보유하고 잠금 A를 요청합니다.

감사해요,

교착 상태는 스레드가 다른 스레드가 완료되기를 기다리고 있을 때 발생하며 그 반대의 경우도 마찬가지입니다.

피하는 방법?
- 중첩된 잠금을 피하세요
- 불필요한 잠금을 피하세요
- 스레드 조인()을 사용하세요.

어떻게 감지합니까?
cmd에서 다음 명령을 실행하세요.

jcmd $PID Thread.print

참조 :괴짜

이해를 위한 고전적이고 매우 간단한 프로그램 이중 자물쇠 상황 :-

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을 호출하면 클래스 게으른 클래스가 초기화되었는지 확인하고 클래스를 초기화하기 시작합니다.메인 스레드는 이제 초기화 된 설정으로 설정하고, 실행 메소드 세트가 true로 초기화 된 배경 스레드를 생성하고 시작하고, 배경 스레드가 완료되기를 기다립니다.

이번에는 클래스가 현재 다른 스레드에 의해 초기화되고 있습니다.이러한 상황에서는 배경 스레드 인 현재 스레드가 초기화가 완료 될 때까지 클래스 객체의 대기합니다.불행히도, 초기화를 수행하는 스레드, 기본 스레드는 배경 스레드가 완료되기를 기다리고 있습니다.두 스레드가 이제 서로를 기다리고 있기 때문에 프로그램은 교착 상태.

교착상태 문제

  • 최초의 컴퓨터 운영 체제는 한 번에 하나의 프로그램 만 실행했습니다.
  • 시스템의 모든 리소스는이 하나의 프로그램에서 사용할 수있었습니다.
  • 나중에 운영 체제
  • 프로그램은 동시에 실행되는 다른 프로그램과의 충돌을 피할 수 있도록 필요한 자원을 미리 지정해야했습니다.
  • 결국 일부 운영 체제는 리소스의 동적 할당을 제공했습니다.
  • 프로그램이 실행되기 시작한 후 추가 자원 할당을 요청할 수 있습니다.
  • 이로 인해 교착상태 문제가 발생했습니다.

자원을 보유하고 세트에서 다른 프로세스가 보유한 리소스를 획득하기를 기다리는 차단 된 프로세스 세트

02 개 이상의 경쟁 행동이 각각 상대방이 끝나기를 기다리는 상황이므로

교착 상태 특성화

  • 상호 배제
  • 보류 및 대기
  • 선점 없음
  • 순환 대기

교착 상태 처리 방법

  • 시스템이 교착 상태에 빠지지 않도록 보장
  • 시스템이 교착 상태에 입력하도록 허용 한 다음 복구하십시오.
  • 문제를 무시하고 시스템에서 교착 상태가 발생하지 않는 척하십시오.UNIX를 포함한 대부분의 운영 체제에서 사용합니다

교착상태 예방

  • 상호 배제 – 공유 가능한 자원에는 필요하지 않습니다.공유할 수 없는 리소스에 대해 보유해야 함

  • 잡고 기다려라 - 프로세스가 리소스를 요청할 때마다 다른 리소스를 보유하지 않도록 보장해야합니다.

  • 선점 없음 - 일부 리소스를 보유하는 프로세스가 즉시 할당 할 수없는 다른 리소스를 요청하는 경우 현재 보유하고있는 모든 리소스가 공개됩니다.

  • 순환 대기 - 모든 리소스 유형의 총 순서를 부과하고 각 프로세스는 열거 순서를 높이기 위해 리소스를 요청해야합니다.

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

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

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

  • 공유 리소스를 사용하기 전에 잠금을 획득하세요.

  • 가능한 한 짧은 시간 동안 자물쇠를 잡고 있습니다.

  • 스레드가 오류를 반환하면 잠금을 해제합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top