Demo Program - Mutex Locks in Python

See What Is the Python Global Interpreter Lock (GIL)? for important information.

#!/usr/bin/python3
# ===================================================================
# from: www.delftstack.com/howto/python/mutex-in-python/
# -------------------------------------------------------------------
# Note:
# 1. The threading module provides a Thread class to create and
#    manage threads. We can either use an extended class (child
#    class of the Thread class) to create an object or create
#    an object using the Thread class directly.
# 2. A child class inherits all of the attributes and functions
#    assigned to a parent class.
# 3. The Thread class has a run() method that is invoked whenever
#    we call the start() function. Extending the Thread class
#    and providing a run() function overrides the run() function in
#    the (parent) Thread class.
# -------------------------------------------------------------------
# Program Output/Description:
#
#   The first thread is now sleeping
#   The second thread is now sleeping
#   First thread is finished
#   Second thread is finished
#
# In this code, the second thread is not released until the first
# thread is done. The second thread waits for the first thread in
# the lock. The global keyword is used in the code because both the
# thread uses it. Note that the print statement comes right after
# the acquire statement, not before, because as long as the thread
# is waiting, it has not finished yet.
#
# Therefore, it is very important to lock the threads. Otherwise, it
# may crash the application if two threads share the same resource
# simultaneously.
# ===================================================================

import threading, time, random

mutex = threading.Lock()

class thread_one(threading.Thread):
    # overides the run function in the Thread class
    def run(self):
        global mutex
        print ("The first thread is now sleeping")
        time.sleep(random.randint(1, 5))
        print("First thread is finished")
        mutex.release()

class thread_two(threading.Thread):
    # overides the run function in the Thread class
    def run(self):
        global mutex
        print ("The second thread is now sleeping")
        time.sleep(random.randint(1, 5))
        mutex.acquire()
        print("Second thread is finished")
  
mutex.acquire()
t1 = thread_one()
t2 = thread_two()
t1.start()
t2.start()