استفاده از lock بر روی object ها

  • مدرس: علی بیگدلی
  • تاریخ انتشار: Jan 06, 2021

در اینجا ، نحوه کنترل دسترسی به منابع مشترک را یاد خواهیم گرفت. کنترل برای جلوگیری از خراب شدن داده ها ضروری است. به عبارت دیگر ، برای جلوگیری از دسترسی همزمان به یک شی ، باید از Lock استفاده کنیم.

. برای اطلاعات بیشتر به این لینک مراجعه نمایید.

قفل کردن object در یکی از دو حالت "قفل شده" یا "قفل نشده" است.در زمانی که در حالت unlocked قرار دارد، دو حالت برای کار بر روی آن وجود دارد. که دو متد پایه aquire وrelease است. وقتی وضعیت شئ unlocked است با انجام عمل acquire بر روی آن به حالت locked تغییر حالت خواهد داد و تا زمان آزاد سازی دیگر توابع و عملکرد ها اجازه دسترسی به آن را نخواهند داشت. این عمل تا زمانی انجام خواهد گرفت تا متد release بر روی شئ مورد نظر انجام شود و اجازه دسترسی را دوباره فعال نماید. عمل release تنها زمانی کاربری دارد که شئ مورد نظر در وضعیت locked قرار داشته باشد. در صورتی که بر روی unlocked عمل release صورت گیرد پیغام خطای RuntimeError نشان داده خواهد شد.

در اینجا کد مثال ما با استفاده از شئ Lock آورده شده است. در کد ، تابع working () یک نمونه Counter را افزایش می دهد ، که یک Lock را کنترل می کند تا از تغییر همزمان حالت داخلی دو رشته جلوگیری کند.

import threading
import time
import logging
import random

logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-9s) %(message)s',)
                    
class Counter(object):
    def __init__(self, start = 0):
        self.lock = threading.Lock()
        self.value = start
    def increment(self):
        logging.debug('Waiting for a lock')
        self.lock.acquire()
        try:
            logging.debug('Acquired a lock')
            self.value = self.value + 1
        finally:
            logging.debug('Released a lock')
            self.lock.release()

def worker(c):
    for i in range(2):
        r = random.random()
        logging.debug('Sleeping %0.02f', r)
        time.sleep(r)
        c.increment()
    logging.debug('Done')

if __name__ == '__main__':
    counter = Counter()
    for i in range(2):
        t = threading.Thread(target=worker, args=(counter,))
        t.start()

    logging.debug('Waiting for worker threads')
    main_thread = threading.currentThread()
    for t in threading.enumerate():
        if t is not main_thread:
            t.join()
    logging.debug('Counter: %d', counter.value)

خروجی:

(Thread-1 ) Sleeping 0.04
(MainThread) Waiting for worker threads
(Thread-2 ) Sleeping 0.11
(Thread-1 ) Waiting for a lock
(Thread-1 ) Acquired a lock
(Thread-1 ) Released a lock
(Thread-1 ) Sleeping 0.30
(Thread-2 ) Waiting for a lock
(Thread-2 ) Acquired a lock
(Thread-2 ) Released a lock
(Thread-2 ) Sleeping 0.27
(Thread-1 ) Waiting for a lock
(Thread-1 ) Acquired a lock
(Thread-1 ) Released a lock
(Thread-1 ) Done
(Thread-2 ) Waiting for a lock
(Thread-2 ) Acquired a lock
(Thread-2 ) Released a lock
(Thread-2 ) Done
(MainThread) Counter: 4

در این مثال ، worker() سعی می کند قفل را سه بار جداگانه بدست آورد و تعداد تلاش های انجام شده برای این کار را محاسبه می کند. در این زمان ، locker() بین نگه داشتن و آزاد شدن قفل می چرخد ، و وقفه کوتاه در هر حالت برای شبیه سازی بار استفاده می شود.

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-9s) %(message)s',)
                    
def locker(lock):
    logging.debug('Starting')
    while True:
        lock.acquire()
        try:
            logging.debug('Locking')
            time.sleep(1.0)
        finally:
            logging.debug('Not locking')
            lock.release()
        time.sleep(1.0)
    return
                    
def worker(lock):
    logging.debug('Starting')
    num_tries = 0
    num_acquires = 0
    while num_acquires < 3:
        time.sleep(0.5)
        logging.debug('Trying to acquire')
        acquired = lock.acquire(0)
        try:
            num_tries += 1
            if acquired:
                logging.debug('Try #%d : Acquired',  num_tries)
                num_acquires += 1
            else:
                logging.debug('Try #%d : Not acquired', num_tries)
        finally:
            if acquired:
                lock.release()
    logging.debug('Done after %d tries', num_tries)

if __name__ == '__main__':
    lock = threading.Lock()

    locker = threading.Thread(target=locker, args=(lock,), name='Locker')
    locker.setDaemon(True)
    locker.start()

    worker = threading.Thread(target=worker, args=(lock,), name='Worker')
    worker.start()

خروجی:

(Locker   ) Starting
(Locker   ) Locking
(Worker   ) Starting
(Worker   ) Trying to acquire
(Worker   ) Try #1 : Not acquired
(Locker   ) Not locking
(Worker   ) Trying to acquire
(Worker   ) Try #2 : Acquired
(Worker   ) Trying to acquire
(Worker   ) Try #3 : Acquired
(Locker   ) Locking
(Worker   ) Trying to acquire
(Worker   ) Try #4 : Not acquired
(Worker   ) Trying to acquire
(Worker   ) Try #5 : Not acquired
(Locker   ) Not locking
(Worker   ) Trying to acquire
(Worker   ) Try #6 : Acquired
(Worker   ) Done after 6 tries

 

ثبت دیدگاه
نام *
ایمیل*
دیدگاه *
0دیدگاه