Cleanly end a thread with blocked i/o in win32?

Jon Wright jonathan.wright at gmail.com
Thu Oct 21 14:35:39 EDT 2004


Trying to work around the lack of pexpect for native windows python I
had a play with os.popen2 and some threads. This looks promising
enough for what I want to do, but I hit on a problem with getting the
script to exit cleanly. Tried replacing popen with subprocess but I am
still confused. Either it needs to be killed from the task manager, or
I get a variety of different complaints and popping up "application
error" windows. I managed to get it to stop with os.abort(), but this
invites a complaint from windows about terminating in an unusual way.
Closing the file descriptors of the child process leads to a crash and
I think I should be sending a kill to the process, although I don't
know how (please tell me).

Would any of you care to have a look at the code below and make
suggestions for tidying it up properly? It also dies nastily if the
child process terminates. Eventually I would like to fire off a
program from a gui, supply input programmatically, depending upon the
unpredicable questions the program might ask, and prompt the user if
the child process asks something unknown. Also process the output into
a graphical form so the user can change options and run the child
again. Makes the crashing a bit of a problem! Entirely different
approaches which can accomplish this task would also be very very
welcome, I tried a telnet to localhost suggestion, but this was
painfully slow on this windows xp machine (using "services for unix"
telnet server). The communicate bit of subprocess only gives me one
chance to talk to the process. Should I be inheriting from subprocess
and editing the communicate method there?

Having googled extensively on this problem it seems that tidying up
this code could be useful to others too?

Thanks!!

Jon
---
import os,sys,time,subprocess
from threading import Thread

out = ""  

class reader(Thread):
   def __init__(self,file_to_read):
      self.file_to_read=file_to_read
      Thread.__init__(self)
   def run(self):
      global out
      while 1:
         i=self.file_to_read.read(1)
         out+=i 
         sys.stdout.write(i) # for debugging

class writer(Thread):
   def __init__(self,file_to_write):
      self.file_to_write=file_to_write
      Thread.__init__(self)
   def run(self):
      global out
      while 1:
         i=sys.stdin.read(1) # for debugging 
         out+=i 
         self.file_to_write.write(i) 

if __name__=="__main__":
   child = subprocess.Popen(sys.argv[1],
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE) 
   # or: child.stdout,child.stdin = os.popen2(sys.argv[1])
   r = reader(child.stdout)
   w = writer(child.stdin)
   r.start()
   w.start()
   while r.isAlive() and w.isAlive():
       try:
          time.sleep(10)
       except:
          print "\n=== in out now ===\n",out,"\n======"
          break
   print r.isAlive(),w.isAlive() # Who died, in or out??
   time.sleep(1)
   print r.isAlive(),w.isAlive() # Who died, in or out??
   print "You fell off of the bottom of the script"



More information about the Python-list mailing list