CountedResource.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. class CountedResource(object):
  2. """
  3. This class is an attempt to combine the RAIA idiom with reference
  4. counting semantics in order to model shared resources. RAIA stands
  5. for "Resource Allocation Is Acquisition" (see 'Effective C++' for a
  6. more in-depth explanation)
  7. When a resource is needed, create an appropriate CountedResource
  8. object. If the resource is already available (meaning another
  9. CountedResource object of the same type already exists), no action
  10. is taken. Otherwise, acquire() is invoked, and the resource is
  11. allocated. The resource will remain valid until all matching
  12. CountedResource objects have been deleted. When no objects of
  13. a particular CountedResource type exist, the release() function for
  14. that type is invoked and the managed resource is cleaned up.
  15. Usage:
  16. Define a subclass of CountedResource that defines the
  17. @classmethods acquire() and release(). In these two
  18. functions, define your resource allocation and cleanup code.
  19. IMPORTANT:
  20. If you define your own __init__ and __del__ methods, you
  21. MUST be sure to call down to the ones defined in
  22. CountedResource.
  23. Notes:
  24. Until we figure out a way to wrangle a bit more functionality
  25. out of Python, you MUST NOT inherit from any class that has
  26. CountedResource as its base class. In debug mode, this will
  27. raise a runtime assertion during the invalid class's call to
  28. __init__(). If you have more than one resource that you want to
  29. manage/access with a single object, you should subclass
  30. CountedResource again. See the example code at the bottom of
  31. this file to see how to accomplish this (This is useful for
  32. dependent resources).
  33. """
  34. @classmethod
  35. def incrementCounter(cls):
  36. try:
  37. cls.RESOURCE_COUNTER += 1
  38. except AttributeError:
  39. cls.RESOURCE_COUNTER = 1
  40. if cls.RESOURCE_COUNTER == 1:
  41. cls.acquire()
  42. @classmethod
  43. def decrementCounter(cls):
  44. try:
  45. cls.RESOURCE_COUNTER_INIT_FAILED
  46. del cls.RESOURCE_COUNTER_INIT_FAILED
  47. except AttributeError:
  48. cls.RESOURCE_COUNTER -= 1
  49. if cls.RESOURCE_COUNTER < 1:
  50. cls.release()
  51. @classmethod
  52. def getCount(cls):
  53. return cls.RESOURCE_COUNTER
  54. @classmethod
  55. def acquire(cls):
  56. pass
  57. @classmethod
  58. def release(cls):
  59. pass
  60. def __init__(self):
  61. cls = type(self)
  62. cls.RESOURCE_COUNTER_INIT_FAILED = True
  63. assert cls.mro()[1] == CountedResource, \
  64. (lambda: \
  65. '%s cannot be subclassed.' \
  66. % cls.mro()[list(cls.mro()).index(CountedResource) - 1].__name__)()
  67. del cls.RESOURCE_COUNTER_INIT_FAILED
  68. self.incrementCounter()
  69. def __del__(self):
  70. self.decrementCounter()