title: How to let a Python thread finish gracefully
body: <p>I'm doing a project involving data collection and logging. I have 2 threads running, a collection thread and a logging thread, both started in main. I'm trying to allow the program to be terminated gracefully when with Ctrl-C. </p>
  
  <p>I'm using a <code>threading.Event</code> to signal to the threads to end their respective loops. It works fine to stop the <code>sim_collectData</code> method, but it doesn't seem to be properly stopping the <code>logData</code> thread. The <code>Collection terminated</code> print statement is never executed, and the program just stalls. (It doesn't end, just sits there).</p>
  
  <p>The second <code>while</code> loop in <code>logData</code> is to make sure everything in the queue is logged. The goal is for Ctrl-C to stop the collection thread immediately, then allow the logging thread to finish emptying the queue, and only then fully terminate the program. (Right now, the data is just being printed out - eventually it's going to be logged to a database).</p>
  
  <p>I don't understand why the second thread never terminates. I'm basing what I've done on this answer: <a href="https://stackoverflow.com/questions/6524459/stopping-a-thread-python">Stopping a thread after a certain amount of time</a>. What am I missing?</p>
  
  <pre><code>def sim_collectData(input_queue, stop_event):
      ''' this provides some output simulating the serial
      data from the data logging hardware. 
      '''
      n = 0
      while not stop_event.is_set():
          input_queue.put("DATA: &lt;here are some random data&gt; " + str(n))
          stop_event.wait(random.randint(0,5))
          n += 1
      print "Terminating data collection..."
      return
  
  def logData(input_queue, stop_event):
      n = 0
  
      # we *don't* want to loop based on queue size because the queue could
      # theoretically be empty while waiting on some data.
      while not stop_event.is_set():
          d = input_queue.get()
          if d.startswith("DATA:"):
              print d
          input_queue.task_done()
          n += 1
  
      # if the stop event is recieved and the previous loop terminates, 
      # finish logging the rest of the items in the queue.
      print "Collection terminated. Logging remaining data to database..."
      while not input_queue.empty():
          d = input_queue.get()
          if d.startswith("DATA:"):
              print d
          input_queue.task_done()
          n += 1
      return
  
  
  def main():
      input_queue = Queue.Queue()
  
      stop_event = threading.Event() # used to signal termination to the threads
  
      print "Starting data collection thread...",
      collection_thread = threading.Thread(target=sim_collectData, args=(input_queue,     stop_event))
      collection_thread.start()
      print "Done."
  
      print "Starting logging thread...",
      logging_thread = threading.Thread(target=logData, args=(input_queue, stop_event))
      logging_thread.start()
      print "Done."
  
      try:
          while True:
          time.sleep(10)
      except (KeyboardInterrupt, SystemExit):
          # stop data collection. Let the logging thread finish logging everything in the queue
          stop_event.set()
  
   main()
  </code></pre>