10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""Thread-local objects.
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi(Note that this module provides a Python version of the threading.local
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi class.  Depending on the version of Python you're using, there may be a
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi faster one available.  You should always import the `local` class from
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi `threading`.)
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThread-local objects support the management of thread-local data.
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiIf you have data that you want to be local to a thread, simply create
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yia thread-local object and use its attributes:
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata = local()
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number = 42
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  42
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiYou can also access the local-object's dictionary:
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.__dict__
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  {'number': 42}
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.__dict__.setdefault('widgets', [])
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  []
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.widgets
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  []
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiWhat's important about thread-local objects is that their data are
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yilocal to a thread. If we access the data in a different thread:
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> log = []
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> def f():
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     items = mydata.__dict__.items()
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     items.sort()
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     log.append(items)
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     mydata.number = 11
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     log.append(mydata.number)
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> import threading
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread = threading.Thread(target=f)
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread.start()
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread.join()
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> log
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  [[], 11]
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiwe get different data.  Furthermore, changes made in the other thread
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidon't affect data seen in this thread:
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  42
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiOf course, values you get from a local object, including a __dict__
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiattribute, are for whatever thread was current at the time the
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiattribute was read.  For that reason, you generally don't want to save
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yithese values across threads, as they apply only to the thread they
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yicame from.
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiYou can create custom local objects by subclassing the local class:
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> class MyLocal(local):
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     number = 2
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     initialized = False
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     def __init__(self, **kw):
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...         if self.initialized:
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...             raise SystemError('__init__ called too many times')
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...         self.initialized = True
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...         self.__dict__.update(kw)
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     def squared(self):
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...         return self.number ** 2
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThis can be useful to support default values, methods and
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiinitialization.  Note that if you define an __init__ method, it will be
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yicalled each time the local object is used in a separate thread.  This
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiis necessary to initialize each thread's dictionary.
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiNow if we create a local object:
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata = MyLocal(color='red')
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiNow we have a default number:
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  2
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yian initial color:
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.color
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  'red'
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> del mydata.color
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiAnd a method that operates on the data:
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.squared()
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  4
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiAs before, we can access the data in a separate thread:
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> log = []
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread = threading.Thread(target=f)
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread.start()
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread.join()
1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> log
1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  [[('color', 'red'), ('initialized', True)], 11]
1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiwithout affecting this thread's data:
1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number
1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  2
1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.color
1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Traceback (most recent call last):
1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...
1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  AttributeError: 'MyLocal' object has no attribute 'color'
1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiNote that subclasses can define slots, but they are not thread
1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yilocal. They are shared across threads:
1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> class MyLocal(local):
1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ...     __slots__ = 'number'
1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata = MyLocal()
1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number = 42
1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.color = 'red'
1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSo, the separate thread:
1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread = threading.Thread(target=f)
1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread.start()
1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> thread.join()
1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiaffects what we see:
1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  >>> mydata.number
1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  11
1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi>>> del mydata
1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi__all__ = ["local"]
1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# We need to use objects from the threading module, but the threading
1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# module may also want to use our `local` class, if support for locals
1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# isn't compiled in to the `thread` module.  This creates potential problems
1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# with circular imports.  For that reason, we don't import `threading`
1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# until the bottom of this file (a hack sufficient to worm around the
1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# potential problems).  Note that almost all platforms do have support for
1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# locals in the `thread` module, and there is no circular import problem
1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# then, so problems introduced by fiddling the order of imports here won't
1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# manifest on most boxes.
1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass _localbase(object):
1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    __slots__ = '_local__key', '_local__args', '_local__lock'
1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __new__(cls, *args, **kw):
1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self = object.__new__(cls)
1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        key = '_local__key', 'thread.local.' + str(id(self))
1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        object.__setattr__(self, '_local__key', key)
1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        object.__setattr__(self, '_local__args', (args, kw))
1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        object.__setattr__(self, '_local__lock', RLock())
1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if (args or kw) and (cls.__init__ is object.__init__):
1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise TypeError("Initialization arguments are not supported")
1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # We need to create the thread dict in anticipation of
1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # __init__ being called, to make sure we don't call it
1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # again ourselves.
1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dict = object.__getattribute__(self, '__dict__')
1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        current_thread().__dict__[key] = dict
1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return self
1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _patch(self):
1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    key = object.__getattribute__(self, '_local__key')
1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    d = current_thread().__dict__.get(key)
1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if d is None:
1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        d = {}
1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        current_thread().__dict__[key] = d
1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        object.__setattr__(self, '__dict__', d)
1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # we have a new instance dict, so call out __init__ if we have
1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # one
1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cls = type(self)
1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if cls.__init__ is not object.__init__:
1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            args, kw = object.__getattribute__(self, '_local__args')
1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            cls.__init__(self, *args, **kw)
1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    else:
1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        object.__setattr__(self, '__dict__', d)
1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass local(_localbase):
1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __getattribute__(self, name):
1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lock = object.__getattribute__(self, '_local__lock')
1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lock.acquire()
1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            _patch(self)
1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return object.__getattribute__(self, name)
1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            lock.release()
1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __setattr__(self, name, value):
1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if name == '__dict__':
1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise AttributeError(
2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                "%r object attribute '__dict__' is read-only"
2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                % self.__class__.__name__)
2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lock = object.__getattribute__(self, '_local__lock')
2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lock.acquire()
2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            _patch(self)
2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return object.__setattr__(self, name, value)
2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            lock.release()
2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __delattr__(self, name):
2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if name == '__dict__':
2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise AttributeError(
2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                "%r object attribute '__dict__' is read-only"
2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                % self.__class__.__name__)
2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lock = object.__getattribute__(self, '_local__lock')
2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lock.acquire()
2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            _patch(self)
2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return object.__delattr__(self, name)
2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            lock.release()
2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __del__(self):
2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        import threading
2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        key = object.__getattribute__(self, '_local__key')
2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # We use the non-locking API since we might already hold the lock
2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # (__del__ can be called at any point by the cyclic GC).
2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            threads = threading._enumerate()
2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except:
2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # If enumerating the current threads fails, as it seems to do
2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # during shutdown, we'll skip cleanup under the assumption
2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # that there is nothing to clean up.
2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return
2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for thread in threads:
2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            try:
2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                __dict__ = thread.__dict__
2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except AttributeError:
2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # Thread is dying, rest in peace.
2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                continue
2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if key in __dict__:
2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                try:
2470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    del __dict__[key]
2480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                except KeyError:
2490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    pass # didn't have anything in this thread
2500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom threading import current_thread, RLock
252