.. ot-topic:: python.advanced.multithreading.mutex :dependencies: python.advanced.multithreading.basics .. include:: Race Conditions, and Mutexes ============================ .. contents:: :local: .. sidebar:: **Documentation** * :doc:`python:library/threading` Mother of All Race conditions: Integer Increment ------------------------------------------------ .. literalinclude:: code/race-condition.py :caption: :download:`code/race-condition.py` .. code-block:: console $ python code/race-condition.py final value: 14784035 |longrightarrow| *Load Modify Store Conflict* Load Modify Store Conflict -------------------------- ====== ==== ====== ==== =========== **CPU A** **CPU B** **Memory** ----------- ----------- ----------- Instr Loc Instr Loc Glob load 42 - - 42 - 42 load 42 42 inc 43 - - 42 - 43 inc 43 42 - 43 store 43 43 store 43 - 43 43 ====== ==== ====== ==== =========== Solution: Mutex (Explicit Acquire/Release) ------------------------------------------ * Mutex (for "MUTual EXclusion"), short: ``Lock`` * Best analogy: toilet door lock .. literalinclude:: code/mutex.py :caption: :download:`code/mutex.py` .. code-block:: console $ python code/mutex.py final value: 20000000 Solution: Mutex (``with`` Statement) ------------------------------------ * Calling ``lock.acquire()`` and ``lock.release()`` manually * |longrightarrow| what if exception is raised in the middle? (Well, integer increments don't usually raise one; you get the point though.) |longrightarrow| This is what the ``with`` statement is there fore (``threading.Lock`` can act as a *context manager*) .. literalinclude:: code/mutex-with.py :caption: :download:`code/mutex-with.py` Dependencies ------------ .. ot-graph:: :entries: python.advanced.multithreading.mutex