>  기사  >  교착상태를 피하는 방법은 무엇입니까?

교착상태를 피하는 방법은 무엇입니까?

coldplay.xixi
coldplay.xixi원래의
2020-06-24 14:33:244453검색

교착상태를 피하는 방법은 무엇입니까?

교착 상태를 방지하는 방법:

두 스레드가 서로 리소스를 해제할 때까지 기다릴 때 교착 상태가 발생합니다. Python 인터프리터는 교착 상태 상황을 모니터링하지 않으며 적극적으로 조치를 취하지 않으므로 다중 스레드 프로그래밍을 수행할 때 교착 상태를 방지하기 위한 조치를 취해야 합니다.

교착 상태가 발생하면 전체 프로그램에서 예외가 발생하지 않으며 프롬프트도 표시되지 않지만 모든 스레드가 차단되어 계속할 수 없습니다.

교착 상태는 매우 쉽게 발생하며, 특히 시스템에 여러 개의 동기화 모니터가 있는 경우 다음 프로그램이 교착 상태를 유발합니다.

import threading
import time
class A:
    def __init__(self):
        self.lock = threading.RLock()
    def foo(self, b):
        try:
            self.lock.acquire()
            print("当前线程名: " + threading.current_thread().name\
                + " 进入了A实例的foo()方法" )     # ①
            time.sleep(0.2)
            print("当前线程名: " + threading.current_thread().name\
                + " 企图调用B实例的last()方法")   # ③
            b.last()
        finally:
            self.lock.release()
    def last(self):
        try:
            self.lock.acquire()
            print("进入了A类的last()方法内部")
        finally:
            self.lock.release()
class B:
    def __init__(self):
        self.lock = threading.RLock()
    def bar(self, a):
        try:
            self.lock.acquire()
            print("当前线程名: " + threading.current_thread().name\
                + " 进入了B实例的bar()方法" )   # ②
            time.sleep(0.2)
            print("当前线程名: " + threading.current_thread().name\
                + " 企图调用A实例的last()方法")  # ④
            a.last()
        finally:
            self.lock.release()
    def last(self):
        try:
            self.lock.acquire()
            print("进入了B类的last()方法内部")
        finally:
            self.lock.release()
a = A()
b = B()
def init():
    threading.current_thread().name = "主线程"
    # 调用a对象的foo()方法
    a.foo(b)
    print("进入了主线程之后")
def action():
    threading.current_thread().name = "副线程"
    # 调用b对象的bar()方法
    b.bar(a)
    print("进入了副线程之后")
# 以action为target启动新线程
threading.Thread(target=action).start()
# 调用init()函数
init()

위 프로그램을 실행하면 그림 1의 효과를 볼 수 있습니다.

교착상태를 피하는 방법은 무엇입니까?

그림 1 교착 상태 효과

그림 1에서 볼 수 있듯이 프로그램은 아래쪽으로 실행될 수도 없고 예외가 발생하지도 않으며 "교착 상태"가 되었습니다. 그 이유는 위 프로그램에서 객체 A와 객체 B의 메서드가 모두 스레드로부터 안전한 메서드이기 때문입니다.

프로그램에는 두 개의 스레드가 실행되고 있습니다. 보조 스레드의 스레드 실행 본문은 action() 함수이고, 메인 스레드의 스레드 실행 본문은 init() 함수입니다(주 프로그램은 init()를 호출합니다. 기능). action() 함수에서는 B 객체가 bar() 메서드를 호출하도록 하고, init() 함수에서는 A 객체가 foo() 메서드를 호출하도록 합니다.

그림 1은 action() 함수가 먼저 실행되고 B 개체의 bar() 메서드를 호출하는 것을 보여줍니다. bar() 메서드에 들어가기 전에 스레드는 B 개체의 Lock을 잠급니다(프로그램이 ② 코드를 실행할 때). , 대리인 스레드는 0.2초 동안 일시 중지됩니다. CPU는 다른 스레드 실행으로 전환하고 A 객체가 foo() 메서드를 실행하도록 하므로 기본 스레드가 A 인스턴스의 foo() 메서드를 실행하기 시작하는 것을 볼 수 있습니다. 스레드는 foo() 메소드에 들어가기 전에 A의 foo() 메소드를 실행합니다. 객체 잠금(프로그램이 코드 ①을 실행할 때 메인 스레드도 0.2초 동안 일시 중지됨).

다음으로 보조 스레드가 먼저 깨어나서 코드 ④에 도달할 때까지 아래쪽으로 계속 실행하며 객체 A의 last() 메서드를 호출하려고 합니다(이 메서드를 실행하기 전에 객체 A의 Lock을 잠가야 합니다). 이때 메인 스레드는 객체 A의 Lock을 유지하고 있으므로 보조 스레드는 차단됩니다.

다음에 메인 스레드가 깨어나서 코드 ③에 도달할 때까지 계속 실행해야 하며 B 개체의 last() 메서드를 호출하려고 합니다(이 메서드를 실행하기 전에 B 개체의 Lock을 먼저 잠가야 함). 현재 보조 스레드는 B 개체에 대한 잠금을 해제하지 않았습니다.

이 시점에서 메인 스레드는 객체 A에 대한 잠금을 유지하고 객체 B가 잠길 때까지 기다리는 반면, 보조 스레드는 객체 B에 대한 잠금을 유지하고 객체 A가 잠길 때까지 기다리는 것으로 보입니다. 서로 먼저 잠금을 해제하므로 교착 상태가 발생합니다.

프로그램에서는 교착상태가 발생하지 않아야 합니다. 프로그램을 작성할 때에는 교착상태를 최대한 피해야 합니다. 아래에는 교착 상태 문제를 해결하는 몇 가지 일반적인 방법이 있습니다.

  1. 여러 잠금을 피하세요. 동일한 스레드에서 여러 잠금을 잠그지 마십시오. 예를 들어, 위의 교착 상태 프로그램에서 메인 스레드는 두 개체 A와 B의 잠금을 잠가야 하고 보조 스레드도 두 개체 A와 B의 잠금을 잠가야 하므로 교착 상태의 숨겨진 위험이 있습니다.

  2. 잠금 순서가 동일합니다. 여러 스레드가 여러 잠금을 잠가야 하는 경우 동일한 순서로 잠금을 요청해야 합니다. 예를 들어, 위의 교착 상태 프로그램에서 메인 스레드는 먼저 객체 A의 잠금을 잠근 다음 객체 B의 잠금을 잠그고 보조 스레드는 먼저 객체 B의 잠금을 잠근 다음 객체 A의 잠금을 잠급니다. 이 잠금 시퀀스는 중첩된 잠금을 쉽게 형성하여 교착 상태로 이어질 수 있습니다. 이 문제는 기본 스레드와 보조 스레드가 동일한 순서로 잠기는 경우 피할 수 있습니다.

  3. 시간 잠금을 사용하세요. 프로그램은 잠금을 위해 acquire() 메서드를 호출할 때 시간 초과 매개변수를 지정할 수 있습니다. 이 매개변수는 교착 상태가 잠금 해제될 수 있도록 시간 초과 초 후에 잠금이 자동으로 해제되도록 지정합니다.

  4. 교착 상태 감지. 교착 상태 감지는 알고리즘 메커니즘에 의존하는 교착 상태 방지 메커니즘으로 주로 순차 잠금이 불가능하고 시간 제한 잠금을 사용할 수 없는 시나리오를 대상으로 합니다.

위 내용은 교착상태를 피하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.