[pygtk] shutting down worker threads

Antoon Pardon Antoon.Pardon at rece.vub.ac.be
Fri Mar 31 18:51:14 WST 2006


On Wed, Mar 29, 2006 at 01:52:01PM -0600, Jason Pepas wrote:
> On Wednesday 29 March 2006 12:21 pm, you wrote:
> > Jason Pepas napisa?(a):
> > > When I want to stop my program, how do I interrupt what the worker
> > > threads are doing to tell them it is time to stop?
> >
> > You can poll shared object for "stop flag" in worker thread (in
> > something like "timer object"). And besides that, you have no other
> > options in Python.
> 
> Damn, I was hoping to be able to use interruption instead of polling.  Oh 
> well...

You can, but doing so has some caveats.

The following is only tested on linux, uses ctypes and will
only interrupt python code, so it won't interrupt a thread while in
a C-extention. It provides an Xthread class with a raize method.
This method can be used from an other thread to raise an exception
in this thread and thus interrupt it.

----
import ctypes
from time import sleep

class TimeOut(Exception):
  pass

class Alarm(Exception):
  pass

import threading

class Xthread(threading.Thread):

    
  def start(self):
    self.__original_run = self.run
    self.run = self.__run 
    threading.Thread.start(self)

  def __run(self):
    self._thrd_id = threading._get_ident()
    try:
      self.__original_run()
    finally:
      self.run = self.__original_run

  def raize(self, excpt):

    Nr = ctypes.pythonapi.PyThreadState_SetAsyncExc(self._thrd_id,
                ctypes.py_object(excpt))
    #print self.id , "Exception Thrown" , Nr
    while Nr > 1:
      #print self.id , "Exception Canceled" , Nr
      ctypes.pythonapi.PyThreadState_SetAsyncExc(self._thrd_id, None)
      sleep(0.1)
      Nr = ctypes.pythonapi.PyThreadState_SetAsyncExc(self._thrd_id,
                  ctypes.py_object(excpt))
    #if Nr == 0:
    #  print self.id , "Exception Canceled" , Nr
    #  ctypes.pythonapi.PyThreadState_SetAsyncExc(self._thrd_id, None)

  def alarm(self, tm):

    alrm = threading.Timer(tm, self.raize, (TimeOut,))
    alrm.start()
    return alrm

if __name__ == "__main__":

  import os
  from random import randint

  class Continue(Xthread):
  
    def run(self):
  
      self.id = os.getpid()
      print self.id, self._thrd_id, "Begin"
      i = 0
      try:
        for _ in xrange(randint(0,20)):
          for e in xrange(4 * 100000):
            i = i + e
        print self.id, "Finished"
      except Alarm:
        print self.id, "Interupted"
  
  lst = [Continue() for _ in xrange(10)]
  
  for T in lst:
    T.start()
  
  try:
    sleep(10)
  finally:
    for T in lst:
      T.raize(Alarm)


More information about the pygtk mailing list