My understanding is that due to the Global Interpreter Lock in cPython, only one thread can ever be executed at any one time. Does this or does this not automatically protected against race conditions, such as the lost update problem?
Just to be clear, I am asking from a theoretical perspective. I would never write threaded code without synchronization.
Due to the GIL, there is only ever one thread per process active to execute Python bytecode; the bytecode evaluation loop is protected by it.
The lock is released every
sys.getcheckinterval() byte codes, at which point a thread switch can take place. This means that for Python code, a thread switch can still take place, but only between byte code instructions. Any code that relies on thread safety needs to take this into account. Actions that can be done in one bytecode can be thread safe, everything else is not.
Even a single byte code instruction can trigger other Python code; for example the line
object[index] can trigger a
__getitem__ call on a custom class, implemented itself in Python. Thus a single
BINARY_SUBSCR opcode is not necessarily thread safe, depending on the object type.