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)를 통해 윈도우 화면 미러링 방법

python winsound를 이용한 윈도우 환경에서 소리 재생 예제

mkfs.fat Device or resource busy 에러 해결법

Embedded Linux USB Ethernet Gadget 사용하기