Package concurrent_tree_crawler :: Package common :: Package threads :: Module rw_lock
[hide private]
[frames] | no frames]

Source Code for Module concurrent_tree_crawler.common.threads.rw_lock

  1  import threading 
  2  #import time ##DEBUG 
  3  #import logging ##DEBUG 
  4   
  5  __author__ = "Mateusz Kobos" 
  6   
  7  """ 
  8  This code is a derivative of the code from ActiveState Code service at the address: 
  9  http://code.activestate.com/recipes/577803-reader-writer-lock-with-priority-for-writers 
 10  and is licensed under the MIT license. 
 11  """ 
 12   
13 -class RWLock:
14 """Synchronization object used in a solution of so-called second 15 readers-writers problem. In this problem, many readers can simultaneously 16 access a share, and a writer has an exclusive access to this share. 17 Additionally, the following constraints should be met: 18 - no reader should be kept waiting if the share is currently opened for 19 reading unless a writer is also waiting for the share, 20 - no writer should be kept waiting for the share longer than absolutely 21 necessary. 22 23 The implementation is based on [1, secs. 4.2.2, 4.2.6, 4.2.7] 24 with a modification -- adding an additional lock (C{self.__readers_queue}) 25 -- in accordance with [2]. 26 27 Sources: 28 1. A.B. Downey: "The little book of semaphores", Version 2.1.5, 2008 29 2. P.J. Courtois, F. Heymans, D.L. Parnas: 30 "Concurrent Control with 'Readers' and 'Writers'", 31 Communications of the ACM, 1971 (via [3]) 32 3. http://en.wikipedia.org/wiki/Readers-writers_problem 33 """ 34
35 - def __init__(self):
36 self.__read_switch = _LightSwitch() 37 self.__write_switch = _LightSwitch() 38 self.__no_readers = threading.Lock() 39 self.__no_writers = threading.Lock() 40 self.__readers_queue = threading.Lock() 41 """A lock giving an even higher priority to the writer in certain 42 cases (see [2] for a discussion)"""
43
44 - def reader_acquire(self):
45 ##DEBUG 46 #logging.info("thread={}: reader_acquire: BEGIN".format(threading.current_thread().name)) 47 self.__readers_queue.acquire() 48 #logging.info("thread={}: reader_acquire: after readers_queue.acquire()".format(threading.current_thread().name)) 49 self.__no_readers.acquire() 50 #logging.info("thread={}: reader_acquire: after no_readers.acquire()".format(threading.current_thread().name)) 51 self.__read_switch.acquire(self.__no_writers) 52 #logging.info("thread={}: reader_acquire: after read_switch.acquire(self.__no_writers)".format(threading.current_thread().name)) 53 self.__no_readers.release() 54 #logging.info("thread={}: reader_acquire: after no_readers.release()".format(threading.current_thread().name)) 55 self.__readers_queue.release()
56 ##DEBUG 57 #logging.info("thread={}: reader_acquire: END".format(threading.current_thread().name)) 58
59 - def reader_release(self):
60 ##DEBUG 61 #logging.info("thread={}: reader_release: BEGIN".format(threading.current_thread().name)) 62 self.__read_switch.release(self.__no_writers)
63 ##DEBUG 64 #logging.info("thread={}: reader_release: END".format(threading.current_thread().name)) 65
66 - def writer_acquire(self):
67 ##DEBUG 68 #logging.info("thread={}: writer_acquire: BEGIN".format(threading.current_thread().name)) 69 self.__write_switch.acquire(self.__no_readers) 70 #logging.info("thread={}: writer_acquire: after write_switch.acquire(self.__no_readers)".format(threading.current_thread().name)) 71 self.__no_writers.acquire()
72 ##DEBUG 73 #logging.info("thread={}: writer_acquire: END".format(threading.current_thread().name)) 74
75 - def writer_release(self):
76 ##DEBUG 77 #logging.info("thread={}: writer_release: BEGIN".format(threading.current_thread().name)) 78 self.__no_writers.release() 79 self.__write_switch.release(self.__no_readers)
80 ##DEBUG 81 #logging.info("{} thread={}: writer_release: END".format(threading.current_thread().name)) 82 83
84 -class _LightSwitch:
85 """An auxiliary "light switch"-like object. The first thread turns on the 86 "switch", the last one turns it off (see [1, sec. 4.2.2] for details)."""
87 - def __init__(self):
88 self.__counter = 0 89 self.__mutex = threading.Lock()
90
91 - def acquire(self, lock):
92 self.__mutex.acquire() 93 self.__counter += 1 94 if self.__counter == 1: 95 lock.acquire() 96 self.__mutex.release()
97
98 - def release(self, lock):
99 self.__mutex.acquire() 100 self.__counter -= 1 101 if self.__counter == 0: 102 lock.release() 103 self.__mutex.release()
104