It all starts with threads sharing the same memory
A race condition occurs when multiple threads can access and change shared data at the same time. Race conditions become a prevalent problem in a multi-threaded context because threads by definition share the same memory.
With multiple threads running concurrently, we don't know the order in which threads access and modify shared data. Therefore the result of program depends heavily on the scheduling algorithm and the order in which threads race to access shared data.
Example
Suppose we have a shared variable x
with a value of 2. Suppose we also have two threads, t1
and t2
.
-
t1
performsx += 3
-
t2
performsx *= 2
If t1
operates on x
before t2
:
- x += 1 (x = 3)
- x *= 2 (x = 6)
If t2
operates on x
before t1
:
- x *= 2 (x = 4)
- x += 1 (x = 5)
OR EVEN WORSE, if threads access data at the same time:
- x *= 2 (x = 4)
OR
- x += 1 (x = 3)
Global Interpreter Lock (GIL)
The GIL is Python's solution to assure thread-safety. It does so by locking the interpreter (e.g. CPython) so that that it’s not possible for another thread to interfere with the current one. That is, only one thread can execute at a time, preventing simultaneous access to shared data.
Top comments (2)
Does GIL ensures the order in which variable should be accessed by threads t1 and t2. I think that issue wasn't addressed here.
Hi, Amaan. The CPython implementation of Python is single-threaded, so you won't run into that issue. If you want to explicitly introduce multi-threading, you would have to use a scheduler to ensure order/timing. See
sched
class: docs.python.org/3/library/sched.htmlEither way, the GIL makes sure no two threads are active at the same time. That's why multi-threaded is concurrent not parallel.
Happy coding!