On 2018-09-12 17:16, Steven D'Aprano wrote:
I'm originally posted this on the Python-Ideas list, but this is probably
more appropriate.


import time
from threading import Thread, local

def func():
     pass

def attach(value):
     func.__params__ = local()
     func.__params__.value = value


def worker(i):
     print("called from thread %s" % i)
     attach(i)
     assert func.__params__.value == i
     time.sleep(3)
     value = func.__params__.value
     if value != i:
         print("mismatch", i, value)

for i in range(5):
     t = Thread(target=worker, args=(i,))
     t.start()

print()





When I run that, each of the threads print their "called from ..."
message, the assertions all pass, then a couple of seconds later they
consistently all raise exceptions:

Exception in thread Thread-1:
Traceback (most recent call last):
   File "/usr/local/lib/python3.5/threading.py", line 914, in
_bootstrap_inner
     self.run()
   File "/usr/local/lib/python3.5/threading.py", line 862, in run
     self._target(*self._args, **self._kwargs)
   File "<stdin>", line 5, in worker
AttributeError: '_thread._local' object has no attribute 'value'



What am I doing wrong?

I've changed the code to:

import time
from threading import Thread, local

def func():
    pass

def attach(value):
    func.__params__ = local()
    func.__params__.value = value

def worker(i):
    print("called from thread %s" % i)
    attach(i)
    print('thread %s before sleep => %s' % (i, func.__params__))
    assert func.__params__.value == i
    time.sleep(1)
    print('thread %s after sleep => %s' % (i, func.__params__))
    time.sleep(1)
    print('thread %s finally => %s' % (i, func.__params__))
print('stored value for thread %s is %s' % (i, getattr(func.__params__, 'value', 'MISSING')))

for i in range(2):
    t = Thread(target=worker, args=(i,))
    t.start()

print()



My output is:

called from thread 0
thread 0 before sleep => <_thread._local object at 0x0000014936FB8C50>
called from thread 1
thread 1 before sleep => <_thread._local object at 0x0000014936FB8CA8>

thread 1 after sleep => <_thread._local object at 0x0000014936FB8CA8>
thread 0 after sleep => <_thread._local object at 0x0000014936FB8CA8>
thread 0 finally => <_thread._local object at 0x0000014936FB8CA8>
stored value for thread 0 is MISSING
thread 1 finally => <_thread._local object at 0x0000014936FB8CA8>
stored value for thread 1 is 1


Note that thread 1 is overwriting the reference to the thread-local storage of thread 0.

It looks like what's happening is that thread 0 ends up trying to read the storage for thread 1, but as it's for a different thread, the contents aren't visible to it.
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to