threadable.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. # -*- test-case-name: twisted.python.test_threadable -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. A module to provide some very basic threading primitives, such as
  6. synchronization.
  7. """
  8. from __future__ import division, absolute_import
  9. from functools import wraps
  10. class DummyLock(object):
  11. """
  12. Hack to allow locks to be unpickled on an unthreaded system.
  13. """
  14. def __reduce__(self):
  15. return (unpickle_lock, ())
  16. def unpickle_lock():
  17. if threadingmodule is not None:
  18. return XLock()
  19. else:
  20. return DummyLock()
  21. unpickle_lock.__safe_for_unpickling__ = True
  22. def _synchPre(self):
  23. if '_threadable_lock' not in self.__dict__:
  24. _synchLockCreator.acquire()
  25. if '_threadable_lock' not in self.__dict__:
  26. self.__dict__['_threadable_lock'] = XLock()
  27. _synchLockCreator.release()
  28. self._threadable_lock.acquire()
  29. def _synchPost(self):
  30. self._threadable_lock.release()
  31. def _sync(klass, function):
  32. @wraps(function)
  33. def sync(self, *args, **kwargs):
  34. _synchPre(self)
  35. try:
  36. return function(self, *args, **kwargs)
  37. finally:
  38. _synchPost(self)
  39. return sync
  40. def synchronize(*klasses):
  41. """
  42. Make all methods listed in each class' synchronized attribute synchronized.
  43. The synchronized attribute should be a list of strings, consisting of the
  44. names of methods that must be synchronized. If we are running in threaded
  45. mode these methods will be wrapped with a lock.
  46. """
  47. if threadingmodule is not None:
  48. for klass in klasses:
  49. for methodName in klass.synchronized:
  50. sync = _sync(klass, klass.__dict__[methodName])
  51. setattr(klass, methodName, sync)
  52. def init(with_threads=1):
  53. """Initialize threading.
  54. Don't bother calling this. If it needs to happen, it will happen.
  55. """
  56. global threaded, _synchLockCreator, XLock
  57. if with_threads:
  58. if not threaded:
  59. if threadingmodule is not None:
  60. threaded = True
  61. class XLock(threadingmodule._RLock, object):
  62. def __reduce__(self):
  63. return (unpickle_lock, ())
  64. _synchLockCreator = XLock()
  65. else:
  66. raise RuntimeError("Cannot initialize threading, platform lacks thread support")
  67. else:
  68. if threaded:
  69. raise RuntimeError("Cannot uninitialize threads")
  70. else:
  71. pass
  72. _dummyID = object()
  73. def getThreadID():
  74. if threadingmodule is None:
  75. return _dummyID
  76. return threadingmodule.currentThread().ident
  77. def isInIOThread():
  78. """Are we in the thread responsible for I/O requests (the event loop)?
  79. """
  80. return ioThread == getThreadID()
  81. def registerAsIOThread():
  82. """Mark the current thread as responsible for I/O requests.
  83. """
  84. global ioThread
  85. ioThread = getThreadID()
  86. ioThread = None
  87. threaded = False
  88. # Define these globals which might be overwritten in init().
  89. _synchLockCreator = None
  90. XLock = None
  91. try:
  92. import threading as threadingmodule
  93. except ImportError:
  94. threadingmodule = None
  95. else:
  96. init(True)
  97. __all__ = ['isInIOThread', 'registerAsIOThread', 'getThreadID', 'XLock']