Are GIL and Thread-Safety synonyms?
After writing GIL - Global Interpreter Lock "GIL - Global Interpreter Lock"), a common question people ask me is:":
So the GIL ensures that my code is thread-safe, doesn't it?
Before I go into the nuts and bolts of it, let's start the other way around and check it with a practical example. Let's create a simple class that adds 1's to a var:
class Adding:def __init__(self):self.added = Falseself.value = 0def has_added(self):return self.addeddef add(self):print "Adding...\n"self.value +=1self.added = Truedef get_value(self):return self.value
Now, let's create a few threads to run an object of that class and see what happens:
from threading import Threaddef do_add(adding):if not adding.has_added():adding.add()adding = Adding()for i in xrange(5):Thread(target=do_add,args=(adding,)).start()
Let's run this code a few times:
$ python thread_safety.py
Adding...$ python thread_safety.py
Adding...Adding...
Ooops! We got it twice. Let's double check , and verify that the value is more than 1:
$ python thread_safety.py
Adding...Value: 1
$ python thread_safety.py
Adding...Adding...
Value: 2
So, the answer to the question is No. What's happening then? If the GIL prevents two threads from running simultaneously, how can this be?
The problem with our code is that we introduced a race-condition. A race-condition happens when two or more threads are trying to access some shared data and then try to change it at the same time. The GIL ensures atomicity by interleaving the threads, meaning they can be stopped in the middle of their execution, and if a race-condition is present then we're in trouble. There are some ways to solve this, and I'll leave you with two simple solutions, to fix this:
P.S. I want to thank Vitor Torres, Ricardo Sousa and Nuno Silva for the reviews.