There are several questions on Stack Overflow which explain why access to global variables is not thread safe in Python, even with the presence of the Global Interpreter Lock.
This reason for this is that the GIL only permits a single Python Interpreter instance to execute bytecode at any one time. However, since many operations on data in memory consist of several byte code operations (they are not atomic), if two threads switch such that one stops running and another resumes, this might take place while the state in memory and the state of the interpreter are not aligned at a synchronization point. (Think “race condition”.)
If the above statement isn’t immediatly clear, there are some good explanations available on this site. Here is one such example.
However, in direct contradiction to this, it is often stated that the purpose of the GIL is to simplify multi-thread programming by preventing race conditions. Here is one such example. (but it this may be – and seems to me to be – a common misconception or misunderstanding)
However, this is not a sufficiently detailed explanation, since while global variables are not protected from race conditions, for the reasons described above, some variables are, and this is frequently stated as common lore.
So – why is access to “not global” (“some”) variables guaranteed to be thread safe? Or yet better, under what conditions is access to a variable guaranteed to be thread safe?
One relatively easy to understand example is that of local variables: Since each function call has its own independent stack frame and set of local variables, clearly one thread cannot create a race condition with another in the context of local variables which have a lifetime which is confined to that of a function call.
Put another way, if multiple threads are dispatched with an entry point of my_function
any variables created during the lifetime of this function call are independent of all other threads running in parallel.
As an extension to this idea, if a reference to a (local or otherwise) variable is passed into multiple functions which execute concurrently, this would not be guaranteed to be thread safe, because two or more threads are holding a reference to the same object in memory. (This is essentially very similar to that of the global variable example.)
Are there any other examples? Or do these two examples sufficiently explain the set of possibilities that must be considered?
4