python thread lock example
python의 threading 모듈에는 thread 동기화를 위한 Lock 객체가 존재한다. Lock 객체에는 특정 Thread가 잠금 상태를 소유하지 않는(모든 스레드가 잠금을 해제 할 수 있음) threading.Lock 과 특정 스레드가 잠금 상태를 소유하는 threading.RLock 그리고 threading.Semaphore가 있다. 이들 모두는 acquire()를 통해 잠금 상태를 획득하고, release()를 통해 잠금 상태를 해제한다.
.acquire(blocking=True, timeout=None)
.release()
다음은 threading.RLock을 사용 예제 코드이다.
Basket에서 여러 스레드들이 사과를 하나씩 가져가는 예제로, Basket에 Lock 객체를
두어 한번에 한 스레드만이 사과를 가져가게 했다.
class cBasket(object):
def __init__(self, apple_count=100):
self.lock = threading.RLock()
self.apple_count = apple_count
def get_apple(self):
self.lock.acquire()
if self.apple_count > 0:
time.sleep(np.random.rand(1))
self.apple_count -= 1
self.lock.release()
return 1
self.lock.release()
return 0
class racing_thread(threading.Thread):
event_flag = None
apple_basket = None
my_apple_count = 0
def run(self):
if self.apple_basket is None or self.event_flag is
None:
return
self.event_flag.wait()
while True:
if self.apple_basket.get_apple() is
1:
self.my_apple_count +=
1
else:
return
def racing_main():
th_pool = []
event_flag = threading.Event()
event_flag.clear()
apple_basket = cBasket(100)
for _ in range(10):
th_pool.append(racing_thread(daemon=True))
for i in range(len(th_pool)):
th_pool[i].apple_basket = apple_basket
th_pool[i].event_flag = event_flag
th_pool[i].start()
event_flag.set()
for i in range(len(th_pool)):
if th_pool[i].is_alive():
th_pool[i].join()
total_apple = 0
for i in range(len(th_pool)):
total_apple += th_pool[i].my_apple_count
print('thread ',i,' has
',th_pool[i].my_apple_count,' apples')
print('total_apple:',total_apple)
실행 결과는 아래와 같다.
thread 0 has 18 apples
thread 1 has 17 apples
thread 2 has 9 apples
thread 3 has 15 apples
thread 4 has 6 apples
thread 5 has 8 apples
thread 6 has 5 apples
thread 7 has 4 apples
thread 8 has 3 apples
thread 9 has 15 apples
total_apple: 100
만약 Lock을 사용하지 않는 경우라면 아래와 같이 전체 사과 개수를 초과하는 이상한 결과가 나올 수 있다.
thread 0 has 12 apples
thread 1 has 14 apples
thread 2 has 15 apples
thread 3 has 13 apples
thread 4 has 11 apples
thread 5 has 12 apples
thread 6 has 6 apples
thread 7 has 10 apples
thread 8 has 8 apples
thread 9 has 8 apples
total_apple: 109
잠금 상태 획득과 해제는 acquire()/release()를 호출하지 않고, with를 통해서도 할 수 있다.
class cBasket(object):
def __init__(self, apple_count=100):
self.lock = threading.RLock()
self.apple_count = apple_count
def get_apple(self):
with self.lock:
if self.apple_count > 0:
time.sleep(np.random.rand(1))
self.apple_count -= 1
return 1
return 0
관련 포스트
댓글
댓글 쓰기