You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

87 lines
2.8 KiB

  1. # Copyright Mateusz Kobos, (c) 2011
  2. # https://code.activestate.com/recipes/577803-reader-writer-lock-with-priority-for-writers/
  3. # released under the MIT licence
  4. import threading
  5. __author__ = "Mateusz Kobos"
  6. class RWLock:
  7. """
  8. Read-Write locking primitive
  9. Synchronization object used in a solution of so-called second
  10. readers-writers problem. In this problem, many readers can simultaneously
  11. access a share, and a writer has an exclusive access to this share.
  12. Additionally, the following constraints should be met:
  13. 1) no reader should be kept waiting if the share is currently opened for
  14. reading unless a writer is also waiting for the share,
  15. 2) no writer should be kept waiting for the share longer than absolutely
  16. necessary.
  17. The implementation is based on [1, secs. 4.2.2, 4.2.6, 4.2.7]
  18. with a modification -- adding an additional lock (C{self.__readers_queue})
  19. -- in accordance with [2].
  20. Sources:
  21. [1] A.B. Downey: "The little book of semaphores", Version 2.1.5, 2008
  22. [2] P.J. Courtois, F. Heymans, D.L. Parnas:
  23. "Concurrent Control with 'Readers' and 'Writers'",
  24. Communications of the ACM, 1971 (via [3])
  25. [3] http://en.wikipedia.org/wiki/Readers-writers_problem
  26. """
  27. def __init__(self):
  28. """
  29. A lock giving an even higher priority to the writer in certain
  30. cases (see [2] for a discussion).
  31. """
  32. self.__read_switch = _LightSwitch()
  33. self.__write_switch = _LightSwitch()
  34. self.__no_readers = threading.Lock()
  35. self.__no_writers = threading.Lock()
  36. self.__readers_queue = threading.Lock()
  37. def reader_acquire(self):
  38. self.__readers_queue.acquire()
  39. self.__no_readers.acquire()
  40. self.__read_switch.acquire(self.__no_writers)
  41. self.__no_readers.release()
  42. self.__readers_queue.release()
  43. def reader_release(self):
  44. self.__read_switch.release(self.__no_writers)
  45. def writer_acquire(self):
  46. self.__write_switch.acquire(self.__no_readers)
  47. self.__no_writers.acquire()
  48. def writer_release(self):
  49. self.__no_writers.release()
  50. self.__write_switch.release(self.__no_readers)
  51. class _LightSwitch:
  52. """An auxiliary "light switch"-like object. The first thread turns on the
  53. "switch", the last one turns it off (see [1, sec. 4.2.2] for details)."""
  54. def __init__(self):
  55. self.__counter = 0
  56. self.__mutex = threading.Lock()
  57. def acquire(self, lock):
  58. self.__mutex.acquire()
  59. self.__counter += 1
  60. if self.__counter == 1:
  61. lock.acquire()
  62. self.__mutex.release()
  63. def release(self, lock):
  64. self.__mutex.acquire()
  65. self.__counter -= 1
  66. if self.__counter == 0:
  67. lock.release()
  68. self.__mutex.release()