title: Script stuck on exit when using atexit to terminate threads
body: <p>I'm playing around with threads on python 3.7.4, and I want to use <code>atexit</code> to register a cleanup function that will (cleanly) terminate the threads.</p>
  
  <p>For example:</p>
  
  <pre><code># example.py
  import threading
  import queue
  import atexit
  import sys
  
  Terminate = object()
  
  class Worker(threading.Thread):
      def __init__(self):
          super().__init__()
          self.queue = queue.Queue()
  
      def send_message(self, m):
          self.queue.put_nowait(m)
  
      def run(self):
          while True:
              m = self.queue.get()
              if m is Terminate:
                  break
              else:
                  print("Received message: ", m)
  
  
  def shutdown_threads(threads):
      for t in threads:
          print(f"Terminating thread {t}")
          t.send_message(Terminate)
      for t in threads:
          print(f"Joining on thread {t}")
          t.join()
      else:
          print("All threads terminated")
  
  if __name__ == "__main__":
      threads = [
          Worker()
          for _ in range(5)
      ]
      atexit.register(shutdown_threads, threads)
  
      for t in threads:
          t.start()
  
      for t in threads:
          t.send_message("Hello")
          #t.send_message(Terminate)
  
      sys.exit(0)
  </code></pre>
  
  <p>However, it seems interacting with the threads and queues in the <code>atexit</code> callback creates a deadlock with some internal shutdown routine:</p>
  
  <pre class="lang-none prettyprint-override"><code>$ python example.py
  Received message:  Hello
  Received message:  Hello
  Received message:  Hello
  Received message:  Hello
  Received message:  Hello
  ^CException ignored in: &lt;module 'threading' from '/usr/lib64/python3.7/threading.py'&gt;
  Traceback (most recent call last):
    File "/usr/lib64/python3.7/threading.py", line 1308, in _shutdown
      lock.acquire()
  KeyboardInterrupt
  Terminating thread &lt;Worker(Thread-1, started 140612492904192)&gt;
  Terminating thread &lt;Worker(Thread-2, started 140612484511488)&gt;
  Terminating thread &lt;Worker(Thread-3, started 140612476118784)&gt;
  Terminating thread &lt;Worker(Thread-4, started 140612263212800)&gt;
  Terminating thread &lt;Worker(Thread-5, started 140612254820096)&gt;
  Joining on thread &lt;Worker(Thread-1, stopped 140612492904192)&gt;
  Joining on thread &lt;Worker(Thread-2, stopped 140612484511488)&gt;
  Joining on thread &lt;Worker(Thread-3, stopped 140612476118784)&gt;
  Joining on thread &lt;Worker(Thread-4, stopped 140612263212800)&gt;
  Joining on thread &lt;Worker(Thread-5, stopped 140612254820096)&gt;
  All threads terminated
  </code></pre>
  
  <p>(the <code>KeyboardInterrupt</code> is me using <code>ctrl-c</code> since the process seems to be hanging indefinitely).</p>
  
  <p>However, if I send the <code>Terminate</code> message before exit(uncomment the line after <code>t.send_message("Hello")</code>), the program doesn't hang and terminates gracefully:</p>
  
  <pre class="lang-none prettyprint-override"><code>$ python example.py
  Received message:  Hello
  Received message:  Hello
  Received message:  Hello
  Received message:  Hello
  Received message:  Hello
  Terminating thread &lt;Worker(Thread-1, stopped 140516051592960)&gt;
  Terminating thread &lt;Worker(Thread-2, stopped 140516043200256)&gt;
  Terminating thread &lt;Worker(Thread-3, stopped 140515961992960)&gt;
  Terminating thread &lt;Worker(Thread-4, stopped 140515953600256)&gt;
  Terminating thread &lt;Worker(Thread-5, stopped 140515945207552)&gt;
  Joining on thread &lt;Worker(Thread-1, stopped 140516051592960)&gt;
  Joining on thread &lt;Worker(Thread-2, stopped 140516043200256)&gt;
  Joining on thread &lt;Worker(Thread-3, stopped 140515961992960)&gt;
  Joining on thread &lt;Worker(Thread-4, stopped 140515953600256)&gt;
  Joining on thread &lt;Worker(Thread-5, stopped 140515945207552)&gt;
  All threads terminated
  </code></pre>
  
  <p>This begs the question, when does this <code>threading._shutdown</code> routine gets executed, relative to <code>atexit</code> handlers?
  Does it make sense to interact with threads in <code>atexit</code> handlers?</p>