Hi,
I’m trying to figure out where in the documentation I should look to know what guarantees I can rely on when writing threaded code.
As examples of questions I want to be able to find answers for:
Example1:
stuff = {}
def thread1(event: Event):
sleep(0.5)
stuff[5] = "cool"
event.set()
def thread2(event: Event):
event.wait()
print("got some new stuff!", stuff[5])
Can I rely on that event.set()
implies a memory barrier so that stuff[5]
is always visible and consistent when read from thread2?
Example 2:
class Thing:
def __init__(self):
self._thing_lock = Lock()
def maybe_do_scary_things(self):
with self._thing_lock:
self._scary()
def _scary(self):
# do things with self and attributes/member of self not accessed elsewhere
pass
If maybe_do_scary_things
is called from multiple threads, under what assumptions is it safe to access self
in maybe_do_scary_things
to get the _thing_lock
attribute and lock it? Can code in _scary
make access to self a race condition here? For example, what if other attributes are added or removed from self
? Is this a bad pattern in general and should I always add one layer of indirection here and keep the lock on a non-shared object to be sure I don’t have a race?
Example 3:
a = False
b = 1
def thread1():
sleep(1)
b = 2
a = True
def thread2():
while not a:
pass
print(b)
I think this is obviously a race and I should not expect thread2 to do anything meaningful, certainly I should not expect it to always print 2
. The problem I have is that I have not been able to find something in the documentation that clearly states that this is indeed a race and what can happen if this code were to be executed.
I’m mostly interested in pointers to where I can find answers to questions like these in the future. I’ve read the threading module documentation but it unfortunate says very little about how threads actually interact and what concurrency guarantees different python objects and synchronization primitives offer.