55 lines
1.4 KiB
Python
55 lines
1.4 KiB
Python
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()
|