Thread의 lock

Posted by on October 30, 2019

Recently by the same author:


Python에서 Singleton 구현

You may find interesting:


Reentrant Lock


Reentrant Lock

Thread Lock


스레드에서 자원을 사용할 때

  • 서로 다른 스레드가 동시에 자원에 접근하면 무결성이 훼손될 수 있다.
  • 스레드를 사용할 때는 자원에 대한 무결성을 보장해야 한다.
  • Python 내장 자료구조중에는 무결성을 보장하는 자료구조 또한 존재
  • Lock을 통해 무결성을 보장할 수 있다.


lock 객체 메서드

  • threading.Lock(): lock 객체 생성
  • .acquire(True): 스레드에서 lock을 잡는 요청
    • 인자에 False를 전달하면 lock을 잡을 때 까지 blocking 되지 않고 다음 로직 수행.
  • .release(): lock을 헤제


2개의 스레드가 lock, release를 반복하는 예시

import time
import logging
import threading

logging.basicConfig(level=logging.DEBUG, format="(%(threadName)s) %(message)s")

def blocking_lock(lock):
    logging.debug("Start blocking lock")

    while True:
        time.sleep(1)
        lock.acquire()

        try:
            logging.debug("Grab it")
            time.sleep(0.5)
        
        finally:
            logging.debug("Release")
            lock.release()


def nonblocking_lock(lock):
    logging.debug("Start nonblocking lock")

    attempt, grab = 0, 0

    while grab < 3:
        time.sleep(1)
        logging.debug("Attempt")
        success = lock.acquire(False)

        try:
            attempt += 1
            
            if success:
                logging.debug("Grap it")
                grab += 1
        
        finally:
            if success:
                logging.debug("Release")
                lock.release()

    logging.debug("Attempt: %s, grab: %s" % (attempt, grab))


def main():
    lock = threading.Lock()

    blocking = threading.Thread(target=blocking_lock, name="blocking", args=(lock,))
    blocking.setDaemon(True)
    blocking.start()

    nonblocking = threading.Thread(target=nonblocking_lock, name="nonblocking", args=(lock,))
    nonblocking.start()


if __name__ == "__main__":
    main()


  • 1개의 lock을 설정
  • blocking_lock 스레드는 1초 쉬고, lock을 잡을 때 까지 대기하는 작업을 반복
    • lock을 0.5초 동안 잡고 release
  • nonblocking_lock은 lock을 잡으려는 시도를 반복
    • attempt와 grab 변수는 lock을 잡으려는 시도, 실제 잡은 횟수를 의미
  • nonblocking_lock이 3번의 lock을 쥐면, 프로그램을 종료


결과

  • nonblocking_lock이 5번의 시도 중 3번의 lock을 획득함을 볼 수 있다.


nonblocking_lock에서 aquire에 False 인자를 전달하지 않으면

  • nonblocking_lock이 lock을 잡을 때 까지 대기하게 되므로 시도 마다 lock을 획득할 수 있다.