and and - 7 months ago 76
Python Question

Python threads and atomic operations

I want to implement a thread with a synchronous

stop()
method.

I've seen versions like this:

class Thread1:
def __init__(self):
self._stop_event = threading.Event()
self._thread = None

def start(self):
self._thread = threading.Thread(target=self._run)
self._thread.start()

def stop(self):
self._stop_event.set()
self._thread.join()

def _run(self):
while not self._stop_event.is_set():
self._work()

def _work(self):
print("working")


But I've read that atomic operations are thread safe and it seems to me that it can be done without
Event
. So I came up with this:

class Thread2:
def __init__(self):
self._working = False
self._thread = None

def start(self):
self._working = True
self._thread = threading.Thread(target=self._run)
self._thread.start()

def stop(self):
self._working = False
self._thread.join()

def _run(self):
while self._working:
self._work()

def _work(self):
print("working")


It think that similar implementation would be considered incorrect in C, because compiler can put
_working
to a register (or even optimize out) and the working thread would never know that the variable has changed. Can something like that happen in Python? Is this implementation correct? I don't aim to avoid events or locks altogether, just want to understand this atomic operations thing.

jb. jb.
Answer Source

As far as I can tell it is also incorrect in Python, as _working can still be put in register or optimized in some other way, or some other thing may happen that would change it's value. Reads and writes th this field could be arbitrarily reordered by the processor.

Well lets say that in multithreading world you shouln't really ask: Why this shouldn't work, but rather Why this is guarranteed to work.

Having said that in most cases multithreading is a little bit easier in CPython, because of GIL that guarantees that:

  • Only one interpreter command is executed at any given time.
  • Forces often memory synchronization between threads.

Bear in mind that GIL is a implementation detail, that might go away if someone rewrites CPython without it.

Also note that the fact that it should implement it this way in any real system.