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


관련 포스트

python thread example

댓글

이 블로그의 인기 게시물

간단한 cfar 알고리즘에 대해

windows에서 간단하게 크롬캐스트(Chromecast)를 통해 윈도우 화면 미러링 방법

쉽게 설명한 파티클 필터(particle filter) 동작 원리와 예제

base64 인코딩 디코딩 예제 c 소스

간단한 칼만 필터(Kalman Filter) 소스 코드와 사용 예제