symbian-qemu-0.9.1-12/python-2.6.1/Lib/_threading_local.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Thread-local objects.
       
     2 
       
     3 (Note that this module provides a Python version of the threading.local
       
     4  class.  Depending on the version of Python you're using, there may be a
       
     5  faster one available.  You should always import the `local` class from
       
     6  `threading`.)
       
     7 
       
     8 Thread-local objects support the management of thread-local data.
       
     9 If you have data that you want to be local to a thread, simply create
       
    10 a thread-local object and use its attributes:
       
    11 
       
    12   >>> mydata = local()
       
    13   >>> mydata.number = 42
       
    14   >>> mydata.number
       
    15   42
       
    16 
       
    17 You can also access the local-object's dictionary:
       
    18 
       
    19   >>> mydata.__dict__
       
    20   {'number': 42}
       
    21   >>> mydata.__dict__.setdefault('widgets', [])
       
    22   []
       
    23   >>> mydata.widgets
       
    24   []
       
    25 
       
    26 What's important about thread-local objects is that their data are
       
    27 local to a thread. If we access the data in a different thread:
       
    28 
       
    29   >>> log = []
       
    30   >>> def f():
       
    31   ...     items = mydata.__dict__.items()
       
    32   ...     items.sort()
       
    33   ...     log.append(items)
       
    34   ...     mydata.number = 11
       
    35   ...     log.append(mydata.number)
       
    36 
       
    37   >>> import threading
       
    38   >>> thread = threading.Thread(target=f)
       
    39   >>> thread.start()
       
    40   >>> thread.join()
       
    41   >>> log
       
    42   [[], 11]
       
    43 
       
    44 we get different data.  Furthermore, changes made in the other thread
       
    45 don't affect data seen in this thread:
       
    46 
       
    47   >>> mydata.number
       
    48   42
       
    49 
       
    50 Of course, values you get from a local object, including a __dict__
       
    51 attribute, are for whatever thread was current at the time the
       
    52 attribute was read.  For that reason, you generally don't want to save
       
    53 these values across threads, as they apply only to the thread they
       
    54 came from.
       
    55 
       
    56 You can create custom local objects by subclassing the local class:
       
    57 
       
    58   >>> class MyLocal(local):
       
    59   ...     number = 2
       
    60   ...     initialized = False
       
    61   ...     def __init__(self, **kw):
       
    62   ...         if self.initialized:
       
    63   ...             raise SystemError('__init__ called too many times')
       
    64   ...         self.initialized = True
       
    65   ...         self.__dict__.update(kw)
       
    66   ...     def squared(self):
       
    67   ...         return self.number ** 2
       
    68 
       
    69 This can be useful to support default values, methods and
       
    70 initialization.  Note that if you define an __init__ method, it will be
       
    71 called each time the local object is used in a separate thread.  This
       
    72 is necessary to initialize each thread's dictionary.
       
    73 
       
    74 Now if we create a local object:
       
    75 
       
    76   >>> mydata = MyLocal(color='red')
       
    77 
       
    78 Now we have a default number:
       
    79 
       
    80   >>> mydata.number
       
    81   2
       
    82 
       
    83 an initial color:
       
    84 
       
    85   >>> mydata.color
       
    86   'red'
       
    87   >>> del mydata.color
       
    88 
       
    89 And a method that operates on the data:
       
    90 
       
    91   >>> mydata.squared()
       
    92   4
       
    93 
       
    94 As before, we can access the data in a separate thread:
       
    95 
       
    96   >>> log = []
       
    97   >>> thread = threading.Thread(target=f)
       
    98   >>> thread.start()
       
    99   >>> thread.join()
       
   100   >>> log
       
   101   [[('color', 'red'), ('initialized', True)], 11]
       
   102 
       
   103 without affecting this thread's data:
       
   104 
       
   105   >>> mydata.number
       
   106   2
       
   107   >>> mydata.color
       
   108   Traceback (most recent call last):
       
   109   ...
       
   110   AttributeError: 'MyLocal' object has no attribute 'color'
       
   111 
       
   112 Note that subclasses can define slots, but they are not thread
       
   113 local. They are shared across threads:
       
   114 
       
   115   >>> class MyLocal(local):
       
   116   ...     __slots__ = 'number'
       
   117 
       
   118   >>> mydata = MyLocal()
       
   119   >>> mydata.number = 42
       
   120   >>> mydata.color = 'red'
       
   121 
       
   122 So, the separate thread:
       
   123 
       
   124   >>> thread = threading.Thread(target=f)
       
   125   >>> thread.start()
       
   126   >>> thread.join()
       
   127 
       
   128 affects what we see:
       
   129 
       
   130   >>> mydata.number
       
   131   11
       
   132 
       
   133 >>> del mydata
       
   134 """
       
   135 
       
   136 __all__ = ["local"]
       
   137 
       
   138 # We need to use objects from the threading module, but the threading
       
   139 # module may also want to use our `local` class, if support for locals
       
   140 # isn't compiled in to the `thread` module.  This creates potential problems
       
   141 # with circular imports.  For that reason, we don't import `threading`
       
   142 # until the bottom of this file (a hack sufficient to worm around the
       
   143 # potential problems).  Note that almost all platforms do have support for
       
   144 # locals in the `thread` module, and there is no circular import problem
       
   145 # then, so problems introduced by fiddling the order of imports here won't
       
   146 # manifest on most boxes.
       
   147 
       
   148 class _localbase(object):
       
   149     __slots__ = '_local__key', '_local__args', '_local__lock'
       
   150 
       
   151     def __new__(cls, *args, **kw):
       
   152         self = object.__new__(cls)
       
   153         key = '_local__key', 'thread.local.' + str(id(self))
       
   154         object.__setattr__(self, '_local__key', key)
       
   155         object.__setattr__(self, '_local__args', (args, kw))
       
   156         object.__setattr__(self, '_local__lock', RLock())
       
   157 
       
   158         if args or kw and (cls.__init__ is object.__init__):
       
   159             raise TypeError("Initialization arguments are not supported")
       
   160 
       
   161         # We need to create the thread dict in anticipation of
       
   162         # __init__ being called, to make sure we don't call it
       
   163         # again ourselves.
       
   164         dict = object.__getattribute__(self, '__dict__')
       
   165         current_thread().__dict__[key] = dict
       
   166 
       
   167         return self
       
   168 
       
   169 def _patch(self):
       
   170     key = object.__getattribute__(self, '_local__key')
       
   171     d = current_thread().__dict__.get(key)
       
   172     if d is None:
       
   173         d = {}
       
   174         current_thread().__dict__[key] = d
       
   175         object.__setattr__(self, '__dict__', d)
       
   176 
       
   177         # we have a new instance dict, so call out __init__ if we have
       
   178         # one
       
   179         cls = type(self)
       
   180         if cls.__init__ is not object.__init__:
       
   181             args, kw = object.__getattribute__(self, '_local__args')
       
   182             cls.__init__(self, *args, **kw)
       
   183     else:
       
   184         object.__setattr__(self, '__dict__', d)
       
   185 
       
   186 class local(_localbase):
       
   187 
       
   188     def __getattribute__(self, name):
       
   189         lock = object.__getattribute__(self, '_local__lock')
       
   190         lock.acquire()
       
   191         try:
       
   192             _patch(self)
       
   193             return object.__getattribute__(self, name)
       
   194         finally:
       
   195             lock.release()
       
   196 
       
   197     def __setattr__(self, name, value):
       
   198         lock = object.__getattribute__(self, '_local__lock')
       
   199         lock.acquire()
       
   200         try:
       
   201             _patch(self)
       
   202             return object.__setattr__(self, name, value)
       
   203         finally:
       
   204             lock.release()
       
   205 
       
   206     def __delattr__(self, name):
       
   207         lock = object.__getattribute__(self, '_local__lock')
       
   208         lock.acquire()
       
   209         try:
       
   210             _patch(self)
       
   211             return object.__delattr__(self, name)
       
   212         finally:
       
   213             lock.release()
       
   214 
       
   215     def __del__(self):
       
   216         import threading
       
   217 
       
   218         key = object.__getattribute__(self, '_local__key')
       
   219 
       
   220         try:
       
   221             threads = list(threading.enumerate())
       
   222         except:
       
   223             # If enumerate fails, as it seems to do during
       
   224             # shutdown, we'll skip cleanup under the assumption
       
   225             # that there is nothing to clean up.
       
   226             return
       
   227 
       
   228         for thread in threads:
       
   229             try:
       
   230                 __dict__ = thread.__dict__
       
   231             except AttributeError:
       
   232                 # Thread is dying, rest in peace.
       
   233                 continue
       
   234 
       
   235             if key in __dict__:
       
   236                 try:
       
   237                     del __dict__[key]
       
   238                 except KeyError:
       
   239                     pass # didn't have anything in this thread
       
   240 
       
   241 from threading import current_thread, RLock