from threading import Thread from random import randint import time # Having multiple Threads running that update a shared resource # without proper Thread synchronisation is risky. # # In this example, 2 worker Threads both try to complete a job # updating the counter variable. One is trying to increment it # to > 1000, while the other is trying to decrement it to < -1000 # # The progam is non-deterministic and unreliable because the # OS Task Scheduler is constantly switching between Threads, # with neither taking precedence. This behaviour can lead to # switching infinitely back-and-forth between the Threads, plus # we have no possible way of predicting the output of the program counter = 1 def worker_a(): global counter while counter < 1000: counter += 1 print(f'Worker A incremented counter by 1, counter = {counter}') time.sleep(randint(0, 1)) def worker_b(): global counter while counter > -1000: counter -= 1 print(f'Worker B decremented counter by 1, counter = {counter}') time.sleep(randint(0, 1)) def start_threads(t1, t2): t1.start() t2.start() t1.join() t2.join() def main(): t0 = time.time() thread1 = Thread(target=worker_a, args=()) thread2 = Thread(target=worker_b, args=()) start_threads(thread1, thread2) t1 = time.time() print(f'Execution time: {t1-t0:.2f}') if __name__ == '__main__': main()