Revision 12 as of 2002-12-14 22:29:00

Clear message

Stopping Threads

I'd like to start this page off with a question. How do you kill one thread from within another? Here's some code that shows the problem:

   1 import threading
   2 import time
   3 
   4 class Worker(threading.Thread):
   5   def __init__(self, eventChannel, eventHandler):
   6     self.eventChannel = eventChannel
   7     self.eventHandler = eventHandler
   8     self.stopFlag = 0
   9 
  10   def shutdown(self):
  11     self.stopFlag = 1
  12 
  13   def start(self):
  14     self.stopFlag = 0
  15     while not self.stopFlag:
  16       event = self.eventChannel.waitEvent() # blocking call
  17       self.eventHandler.dispatchEvent(event)
  18 
  19 
  20 eventChannel = EventChannel()
  21 eventHandler = EventHandler()
  22 worker = Worker(eventChannel, eventHandler)
  23 worker.start()
  24 time.sleep(20)
  25 worker.shutdown()

The problem here is that EventChannel.waitEvent() is a blocking operation. So if no event ever arrives, then our worker thread never stops. (EventChannel and EventHandler are classes I've invented for this example)

Suggestions

  def shutdown(self):
    self.stopFlag = 1
    self.eventChannel.push_event(NullEvent())

   1 import Queue, threading, traceback
   2 
   3 class StopMarker:
   4     """This is used as an individual stopper item."""
   5     
   6 class Worker(threading.Thread):
   7     """Get items from a queue and call the handler with the item.
   8     Errors in the handler are printed to stderr, the thread
   9     continues to run.
  10     An individual stop marker is used, so you can pass everyting
  11     as item (including None).
  12     """
  13     
  14     def __init__(self, handler):
  15         """Initialize Thread object and worker."""
  16         threading.Thread.__init__(self)
  17         self.running = 1
  18         self.handler = handler
  19         self.queue   = Queue.Queue()
  20         self.stopper = StopMarker()
  21     
  22     def run(self):
  23         """Worker loop. Errors in the handler are printed to
  24         stderr and the thread continues with the next item."""
  25         while self.running:
  26             try:
  27                 item = self.queue.get()
  28                 if item is self.stopper:
  29                     break
  30                 else:
  31                     self.handler(item)
  32             except:
  33                 traceback.print_exc()
  34     
  35     def stop(self):
  36         """Stop the worker thread and wait until it terminates.
  37         (Waits until last item is processed)"""
  38         self.queue.put(self.stopper)    #stopper item, then...
  39         self.join()                     #wait until the thread has shutdown
  40 
  41     def put(self, item):
  42         """Put an item in the queue to be processed by the handler."""
  43         self.queue.put(item)
  44 
  45 if __name__ == '__main__':
  46     def printer(item):
  47         print "printer(%r)" % item
  48     
  49     w = Worker(printer)
  50     w.start()
  51     for i in range(10):
  52         w.put(i)
  53     w.stop()

Call to C function blocks all threads

I have a C module that does database queries. Those queries go off to an SQL server to be processed. I would like to use my query function within threads and to have it work like time.sleep(), that is, block the current thread until it finishes but allow other threads to continue operation. I haven't seen this issue addressed in any of the books I have.

Resources

Unable to edit the page? See the FrontPage for instructions.