Lock을 사용한 스레드 간 동기화
# 스레드 동기화(Thread Synchronization)를 위한 Lock 사용 성공 예제
import logging
from concurrent.futures import ThreadPoolExecutor
import time
import threading
class DataStore:
# 공유 변수(value)
def __init__(self):
self.value = 0
# Lock 선언
self._lock = threading.Lock()
# 변수 업데이트 함수
def update(self, n):
logging.info("Thread %s: starting update", n)
# 뮤텍스 & Lock 동기화(Thread synchronization) 사용
# Lock 획득
self._lock.acquire()
logging.info("Thread %s has lock", n)
local_copy = self.value
local_copy += 1
time.sleep(0.1)
self.value = local_copy
logging.info("Thread %s about to release lock", n)
# Lock 반환
self._lock.release()
logging.info("Thread %s: finishing update", n)
if __name__ == "__main__":
# Logging format 설정
format = "%(asctime)s: %(message)s"
logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S")
# 클래스 인스턴스화
store = DataStore()
logging.info("Testing update. Starting value is %d.", store.value)
# With Context 시작
with ThreadPoolExecutor(max_workers=2) as executor:
for n in ['First', 'Second', 'Third']:
executor.submit(store.update, n)
logging.info("Testing update. Ending value is %d.", store.value)
Python
복사
클래스 DataStore는 공유 변수 self.value와 lock 객체 self._lock을 소유한다. update 메소드는 스레드가 해당 객체의 value를 안전하게 변경하는 방법을 보여준다. 이 메소드는 self._lock.acquire()를 사용하여 lock을 획득하고, 작업이 끝나면 self._lock.release()를 사용하여 lock을 반환한다. 이런 방식으로, 한 번에 하나의 스레드만 value를 수정할 수 있도록 동기화한다.
메인 함수에서는 ThreadPoolExecutor를 사용하여 세 개의 스레드를 생성하고, 각 스레드에서 DataStore 객체의 update 메소드를 호출한다. 이때, 인자로 'First', 'Second', 'Third'를 전달한다.
스레드가 update 메소드를 호출할 때마다, 해당 스레드는 lock을 획득하여 value를 안전하게 1 증가시키고, lock을 반환한다. 이로 인해 각 스레드의 연산이 겹치지 않고 순차적으로 실행되어, value 값이 올바르게 증가한다.
마지막으로, 모든 스레드의 작업이 완료된 후 value의 최종 값을 출력하여, 각 스레드가 value를 제대로 갱신했음을 확인한다. 이 코드를 실행하면, 세 개의 스레드가 각각 한 번씩 value를 증가시키므로, 최종 value는 3이 될 것이다. Lock을 사용하지 않은 실패 예제 코드는 최종 value로 2가 나온다.