2020년 8월 16일 일요일

Thread lock(critical section) in Python


Thread 사용에 있어서 임계영역의 필요성

아래와 같은 예제가 있습니다.  전역변수 account_balance 에 함수 안에서 더하고 빼는 과정을 하면서 최종적으로는 0이 되는 상태를 유지합니다.

import time
import threading
account_balance = 0

def change_account_balance(delta):
	global account_balance
	account_balance -= delta
	print("+",threading.currentThread().getName(),account_balance)
	account_balance += delta
	print("-",threading.currentThread().getName(),account_balance)

threads = [threading.Thread(target=change_account_balance, args=[3]) for i in range(10)]
for thread in threads:
	thread.start()
thread.join()


그러나 실제 실행해보면 10개의 thread가 서로 경쟁을 하면서 전역 변수값을 수정하게 됩니다.

+ Thread-1 -3
- Thread-1 0
+ Thread-2 -3
+ Thread-3 -6
- Thread-2 -3
- Thread-3 -3
+ Thread-5 -6
+ Thread-4 -6
- Thread-5 -6
+ Thread-7 -9
+ Thread-6 -9
- Thread-4 -6
- Thread-7 -9
+ Thread-10 -12
+ Thread-9 -12
- Thread-6 -9
+ Thread-8 -9
- Thread-10 -6
- Thread-8 0


임계 영역을 설정하는 방법

1. lock변수를 정의하고 threading.Lock() 

2. with 키워드를 사용하거나 acquire() 메소드를 사용합니다.


첫번째 방법(with 키워드 사용)

import time
import threading
account_balance = 0
account_balance_lock = threading.Lock()

def change_account_balance_sf1(delta):
	global account_balance
	with account_balance_lock:
		account_balance -= delta
		print("+",threading.currentThread().getName(),account_balance)
		account_balance += delta
		print("-",threading.currentThread().getName(),account_balance)

threads = [threading.Thread(target=change_account_balance_sf1, args=[3]) for i in range(10)]
for thread in threads:
	thread.start()
thread.join()

결과

+ Thread-1 -3
- Thread-1 0
+ Thread-2 -3
- Thread-2 0
+ Thread-3 -3
- Thread-3 0
+ Thread-4 -3
- Thread-4 0
+ Thread-5 -3
- Thread-5 0
+ Thread-6 -3
- Thread-6 0
+ Thread-7 -3
- Thread-7 0
+ Thread-8 -3
- Thread-8 0
+ Thread-9 -3
- Thread-9 0
+ Thread-10 -3
- Thread-10 0


두번째 방법(acquire() 메소드를 사용)

import time
import threading
account_balance = 0
account_balance_lock = threading.Lock()

def change_account_balance_sf2(delta):
	global account_balance
	account_balance_lock.acquire()
	account_balance -= delta
	print("+",threading.currentThread().getName(),account_balance)
	account_balance += delta
	print("-",threading.currentThread().getName(),account_balance)
	account_balance_lock.release()

threads = [threading.Thread(target=change_account_balance_sf2, args=[3]) for i in range(10)]
for thread in threads:
	thread.start()
thread.join()

결과

+ Thread-1 -3
- Thread-1 0
+ Thread-2 -3
- Thread-2 0
+ Thread-3 -3
- Thread-3 0
+ Thread-4 -3
- Thread-4 0
+ Thread-5 -3
- Thread-5 0
+ Thread-6 -3
- Thread-6 0
+ Thread-7 -3
- Thread-7 0
+ Thread-8 -3
- Thread-8 0
+ Thread-9 -3
- Thread-9 0
+ Thread-10 -3
- Thread-10 0


댓글 없음:

댓글 쓰기