티스토리 뷰


락은 기본적으로 한 스레드에서 잠금과 해제 사이의 구간을 처리할 때, 


같은 락을 열고 들어와야 하는 다른 스레드의 간섭을 배제하는 용도로 쓴다고 했다. 


그런데 이 과정이 특별한 언어적인 장치가 아니라 API 콜에 의존하고 있다는 문제가 있다. 


무슨 말이냐면 어떤 함수의 도입부에서 락을 걸고 리턴하기 직전에 락을 해제하는데, 


이 함수가 재귀호출을 하는 경우가 있을 수 있다는 말이다.


이 경우에 첫번째 재귀 호출에서 앞서 걸린 락 때문에 스레드가 블럭되고, 영영 해당 락을 해제하지 못하는 문제가 생긴다. 


RLock은 이 문제를 해결하기 위한 Lock의 변종이다. RLock은 이미 잠긴 상태에서도 자신을 잠그려는 스레드가 이미 자신을 잠근 스레드라면 잠김 수를 1올리면서 즉시 리턴하는 락이다.



import threading
import time


class Worker:
def __init__(self):
self.count = 1
self.r_lock = threading.RLock()

def increase(self):
with self.r_lock:
print(f"modifying A : RLock Acquired:{self.r_lock}")
while self.count < 5:
self.count += 1
print(f"modifying A : increasing count:{self.count}")
time.sleep(1)
print(f"modifying A : RLock Released:{self.r_lock}")

def decrease(self):
with self.r_lock:
print(f"modifying B : RLock Acquired:{self.r_lock}")
while self.count > -5:
self.count -= 1
print(f"modifying B : decreasing count:{self.count}")
time.sleep(1)
print(f"modifying B : RLock Released:{self.r_lock}")

def modify_both(self):
with self.r_lock:
print(f"RLock acquired, modifying A and B {self.r_lock}")
self.increase()
self.decrease()
print(f"RLock released modifying A and B {self.r_lock}")


worker_a = Worker()
worker_a.modify_both()



with 를 통해서 aquire, release 를 컨텍스트 매니저를 통해


안전하게 구현이 된다.


락과 릴리즈의 복잡한 요청 구현 없이 재귀적인 방식에도 스레드를 안정적으로 실행하고 있다.


코드도 간결하며 유지관리도 쉽다.




댓글