Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is modifying a class variable in python threadsafe?

Tags:

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?

like image 343
Tom Avatar asked Jul 02 '09 06:07

Tom


1 Answers

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) 
like image 185
Ants Aasma Avatar answered Oct 12 '22 02:10

Ants Aasma