Python flows and atomic operations

I want to implement a thread with a synchronous method stop().

I saw the following versions:

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 read that atomic operations are thread safe, and it seems to me that this 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")

He believes that such an implementation will be considered incorrect in C, because the compiler can put _workinginto the register (or even optimize), and the worker thread will never know that the variable has changed. Could something like this happen in Python? Is this implementation correct? I'm not going to avoid events or locks at all, I just want to understand this thing related to atoms.

+4
source share
2

, Python, _working - , - , . , .

, : , .

, CPython , - GIL, , :

  • .
  • .

, GIL - , , - CPython .

, , .

+1

, , .

class Worker(threading.Thread):
    quit = False

    def __init__(self, ...):
        super().__init__()
        self.cond = threading.Condition()
        ...

    def delay(self, seconds):
        deadline = time.monotonic() + seconds
        with self.cond:
            if self.quit:
                raise SystemExit()
            if time.monotinic() >= deadline:
                return
            self.cond.wait(time.monotonic() - deadline)

    def run(self):
        while not self.quit:
            # work here
            ...

            # when delay is needed
            self.delay(123)

    def terminate(self):
        with self.cond:
            self.quit = True
            self.cond.notify_all()
        self.join()

:

worker = Worker()
worker.start()
...
# finally
worker.terminate()

, , , self.cond, .

0

Source: https://habr.com/ru/post/1536928/


All Articles