I was reading this question (which you do not have to read because I will copy what is there... I just wanted to give show you my inspiration)...
So, if I have a class that counts how many instances were created:
class Foo(object): instance_count = 0 def __init__(self): Foo.instance_count += 1
My question is, if I create Foo objects in multiple threads, is instance_count going to be correct? Are class variables safe to modify from multiple threads?
It's not threadsafe even on CPython. Try this to see for yourself:
import threading class Foo(object): instance_count = 0 def inc_by(n): for i in xrange(n): Foo.instance_count += 1 threads = [threading.Thread(target=inc_by, args=(100000,)) for thread_nr in xrange(100)] for thread in threads: thread.start() for thread in threads: thread.join() print(Foo.instance_count) # Expected 10M for threadsafe ops, I get around 5M
The reason is that while INPLACE_ADD is atomic under GIL, the attribute is still loaded and store (see dis.dis(Foo.__init__)). Use a lock to serialize the access to the class variable:
Foo.lock = threading.Lock() def interlocked_inc(n): for i in xrange(n): with Foo.lock: Foo.instance_count += 1 threads = [threading.Thread(target=interlocked_inc, args=(100000,)) for thread_nr in xrange(100)] for thread in threads: thread.start() for thread in threads: thread.join() print(Foo.instance_count)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With