#!/usr/bin/env python3 # This demonstrates disrupting threading.Condition's __enter__ and __exit__, # which results in deadlocks. # # Tested on Linux import threading import os import signal import time import traceback # Easier to see the behavior with a non re-entrant lock. cond = threading.Condition(threading.Lock()) def monitor_thread(): while True: if not cond.acquire(timeout=2): print("cannot aquire lock!") continue try: if not cond.wait(timeout=2): print("timeout waiting for notification") else: print("heartbeat") finally: cond.release() def sigint_thread(): """Simulates several rapid Ctrl+C presses. It makes this demo more reliable than making the user spam Ctrl+C You might need to adjust the sleep() times a bit for your system.""" pid = os.getpid() time.sleep(0.5) for i in range(20): time.sleep(0.1) # Might need to adjust this value a bit os.kill(pid, signal.SIGINT) # Simulate Ctrl+C monitor = threading.Thread(target=monitor_thread) monitor.start() sigint = threading.Thread(target=sigint_thread) sigint.start() # We notify as fast as we can. i = 0 while True: try: # Eventually we'll end up with cond in a locked state, # and we will no longer be able to call notify() with cond: cond.notify() except KeyboardInterrupt: print("ouch", i) i += 1 monitor.join() sigint.join()