Python 잠 금 방지 방법

문제.
다 중 스 레 드 프로그램 을 쓰 고 있 습 니 다.스 레 드 는 한 번 에 여러 개의 자 물 쇠 를 가 져 와 야 합 니 다.이 때 잠 금 문 제 를 어떻게 피 할 수 있 습 니까?
해결 방안
다 중 스 레 드 프로그램 에서 잠 금 문제 의 큰 부분 은 스 레 드 가 여러 개의 자 물 쇠 를 동시에 가 져 오기 때 문 입 니 다.예 를 들 어 하나의 스 레 드 가 첫 번 째 자 물 쇠 를 가 져 온 다음 에 두 번 째 자 물 쇠 를 가 져 올 때 차단 이 발생 하면 이 스 레 드 는 다른 스 레 드 의 실행 을 막 아서 전체 프로그램 이 가사 할 수 있 습 니 다.잠 금 문 제 를 해결 하 는 방안 은 프로그램의 모든 잠 금 에 유일한 id 를 분배 한 다음 에 오름차 규칙 에 따라 여러 개의 잠 금 만 사용 할 수 있 도록 하 는 것 입 니 다.이 규칙 은 문맥 관리 자 를 사용 하 는 것 이 매우 쉽 습 니 다.예 를 들 어 다음 과 같 습 니 다.

import threading
from contextlib import contextmanager

# Thread-local state to stored information on locks already acquired
_local = threading.local()

@contextmanager
def acquire(*locks):
  # Sort locks by object identifier
  locks = sorted(locks, key=lambda x: id(x))

  # Make sure lock order of previously acquired locks is not violated
  acquired = getattr(_local,'acquired',[])
  if acquired and max(id(lock) for lock in acquired) >= id(locks[0]):
    raise RuntimeError('Lock Order Violation')

  # Acquire all of the locks
  acquired.extend(locks)
  _local.acquired = acquired

  try:
    for lock in locks:
      lock.acquire()
    yield
  finally:
    # Release locks in reverse order of acquisition
    for lock in reversed(locks):
      lock.release()
    del acquired[-len(locks):]
이 상하 문 관리 자 를 어떻게 사용 합 니까?정상 적 인 경로 에 따라 자물쇠 대상 을 만 들 수 있 지만 하나의 자물쇠 든 여러 개의 자물쇠 든acquire() 함수 로 자 물 쇠 를 신청 할 수 있 습 니 다.예 를 들 어 다음 과 같 습 니 다.

import threading
x_lock = threading.Lock()
y_lock = threading.Lock()

def thread_1():
  while True:
    with acquire(x_lock, y_lock):
      print('Thread-1')

def thread_2():
  while True:
    with acquire(y_lock, x_lock):
      print('Thread-2')

t1 = threading.Thread(target=thread_1)
t1.daemon = True
t1.start()

t2 = threading.Thread(target=thread_2)
t2.daemon = True
t2.start()
이 코드 를 실행 하면 서로 다른 함수 에서 다른 순서 로 자 물 쇠 를 가 져 와 도 잠 금 이 발생 하지 않 는 다 는 것 을 알 게 될 것 입 니 다.첫 번 째 코드 에서 우 리 는 이 자물쇠 들 을 정렬 하 는 것 이 관건 이다.정렬 을 통 해 사용자 가 어떤 순서 로 자 물 쇠 를 요청 하 든 이 자 물 쇠 는 고정된 순서에 따라 가 져 옵 니 다.여러 acquire()작업 이 내장 되 어 호출 되면 스 레 드 로 컬 저장 소(TLS)를 통 해 잠재 적 인 잠 금 문 제 를 감지 할 수 있 습 니 다.만약 당신 의 코드 가 이렇게 쓰 여 있다 면:

import threading
x_lock = threading.Lock()
y_lock = threading.Lock()

def thread_1():

  while True:
    with acquire(x_lock):
      with acquire(y_lock):
        print('Thread-1')

def thread_2():
  while True:
    with acquire(y_lock):
      with acquire(x_lock):
        print('Thread-2')

t1 = threading.Thread(target=thread_1)
t1.daemon = True
t1.start()

t2 = threading.Thread(target=thread_2)
t2.daemon = True
t2.start()
이 버 전의 코드 를 실행 하면 스 레 드 가 무 너 질 것 입 니 다.이상 한 정 보 는 다음 과 같 을 수 있 습 니 다.

Exception in thread Thread-1:
Traceback (most recent call last):
 File "/usr/local/lib/python3.3/threading.py", line 639, in _bootstrap_inner
  self.run()
 File "/usr/local/lib/python3.3/threading.py", line 596, in run
  self._target(*self._args, **self._kwargs)
 File "deadlock.py", line 49, in thread_1
  with acquire(y_lock):
 File "/usr/local/lib/python3.3/contextlib.py", line 48, in __enter__
  return next(self.gen)
 File "deadlock.py", line 15, in acquire
  raise RuntimeError("Lock Order Violation")
RuntimeError: Lock Order Violation
>>>
붕괴 의 원인 은 모든 스 레 드 에 자신 이 가 져 온 자 물 쇠 를 기록 하고 있 기 때문이다.acquire()함 수 는 이전에 가 져 온 자물쇠 목록 을 검사 합 니 다.자 물 쇠 는 오름차 순 으로 배열 되 어 있 기 때문에 함 수 는 이전에 가 져 온 자물쇠 의 id 가 새로 신청 한 자물쇠 보다 작 을 것 이 라 고 생각 합 니 다.이 때 이상 이 발생 합 니 다.
토론 하 다.
잠 금 은 모든 다 중 스 레 드 프로그램 이 직면 하 는 문제 이다.경험 에 의 하면 가능 한 한 모든 라인 이 하나의 자물쇠 만 동시에 유지 할 수 있 도록 보장 하면 프로그램 이 자물쇠 문제 에 시 달리 지 않 을 것 이다.일단 스 레 드 가 있 으 면 여러 개의 자 물 쇠 를 동시에 신청 하면 모든 것 을 예측 할 수 없다.
잠 금 검사 와 복 구 는 우아 한 해결 방안 이 거의 없 는 확장 화제 이다.비교적 자주 사용 되 는 자물쇠 검사 와 복구 방안 은 문지기 계수 기 를 도입 하 는 것 이다.스 레 드 가 정상적으로 작 동 할 때 일정 시간 마다 계수 기 를 리 셋 하고 잠 금 이 발생 하지 않 은 상태 에서 모든 것 이 정상적으로 진행 된다.잠 금 이 발생 하면 계수 기 를 초기 화 할 수 없어 타이머 가 시간 을 초과 하면 프로그램 은 다시 시작 을 통 해 정상 상태 로 돌아 갑 니 다.
잠 금 을 피 하 는 것 은 또 다른 잠 금 문 제 를 해결 하 는 방식 입 니 다.프로 세 스 가 잠 금 을 가 져 올 때 대상 id 의 오름차 순 으로 엄 격 히 배열 하여 얻 을 수 있 습 니 다.수학 적 증명 을 통 해 프로그램 이 잠 금 상태 에 들 어가 지 않도록 합 니 다.증명 은 독자 에 게 연습 으로 남 겨 두 었 다.잠 금 을 피 하 는 주요 사상 은 단순히 대상 id 가 증가 하 는 순서에 따라 잠 금 을 추가 하면 순환 의존 이 발생 하지 않 고 순환 의존 은 잠 금 의 필수 조건 이 므 로 프로그램 이 잠 금 상태 에 들 어가 지 않도록 하 는 것 이다.
다음은 스 레 드 잠 금 에 관 한 전형 적 인 문제 인'철학 자 식사 문제'를 본 절의 마지막 예 로 들 겠 습 니 다.제목 은 이 렇 습 니 다.다섯 명의 철학 자가 한 테이블 앞 에 둘 러 앉 아 있 고 모든 사람 앞 에 밥 한 그릇 과 젓가락 이 있 습 니 다.여기 서 모든 철학 자 들 은 하나의 독립 된 라인 이 라 고 볼 수 있 고,젓가락 마다 하나의 자물쇠 라 고 볼 수 있다.모든 철학 자 는 정좌,사고,식사 세 가지 상태 중 하나 에 처 할 수 있다.주의해 야 할 것 은 모든 철학 자 들 이 밥 을 먹 을 때 두 개의 젓가락 이 필요 하 다 는 것 이다.이런 문 제 는 모든 철학 자 들 이 자신의 왼쪽 젓가락 을 들 면 그들 다섯 명 은 젓가락 하 나 를 들 고 굶 어 죽 을 때 까지 앉 아 있 을 수 밖 에 없다 는 것 이다.이때 그들 은 자물쇠 상태 로 들 어 갔다.다음은'철학 자 식사 문제'를 해결 하 는 간단 한 잠 금 방지 체 제 를 사용 하 는 실현 이다.

import threading

# The philosopher thread
def philosopher(left, right):
  while True:
    with acquire(left,right):
       print(threading.currentThread(), 'eating')

# The chopsticks (represented by locks)
NSTICKS = 5
chopsticks = [threading.Lock() for n in range(NSTICKS)]

# Create all of the philosophers
for n in range(NSTICKS):
  t = threading.Thread(target=philosopher,
             args=(chopsticks[n],chopsticks[(n+1) % NSTICKS]))
  t.start()
마지막 으로 자물쇠 가 꺼 지지 않도록 모든 자물쇠 추가 작업 은acquire() 함 수 를 사용 해 야 한 다 는 것 을 주의해 야 한다.만약 코드 중의 일부분 이 acquire 함 수 를 돌아 서 직접 자 물 쇠 를 신청한다 면 전체 자물쇠 피 하 는 메커니즘 은 작용 하지 않 을 것 이다.
이상 은 Python 의 잠 금 방지 방법 에 대한 상세 한 내용 입 니 다.Python 의 잠 금 방지 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기