I have a Python program that has some threads that do blocking calls. For example:
#!/usr/bin/python
import threading, tty, sys, os, signal
# super-awesome thread launcher (re-inventing the wheel because I'm
# too lazy to research what they called this)
class Launch(threading.Thread):
def __init__(self, f):
threading.Thread.__init__(self)
self.f = f
self.start()
def run(self):
self.f()
# structure to hold unprocessed chars
Term_Lock = threading.Lock()
Term_Cond = threading.Condition(Term_Lock)
Term_In = []
# launch a thread to retrieve characters from the terminal
tty.setraw(sys.stdin.fileno())
@Launch
def Stdin_Reader():
while True:
c = sys.stdin.read(1)
with Term_Lock:
Term_In.append(c)
Term_Cond.notify()
# main thread
c = None
with Term_Lock:
Term_Cond.wait(1)
if Term_In:
c = Term_In.pop(0)
if c:
print "You pressed '%s'\r" % c
else:
print "You were too slow!\r"
# Lord have mercy on my soul
os.kill(os.getpid(), signal.SIGKILL)
Although this program works just fine, that os.kill()
at the end is a little bit unsettling. I have programmed in many other languages, and never seen this sort of issue before. I don't have a problem with the language inventor removing the _Exit call that should happen at the end of the main thread. But then to completely hide _Exit from the system APIs, now that's nerve.
Indeed, what we're seeing is basic questions about how to stop a program in a reasonable way. For example:
Exit a process while threads are sleeping
They say use Python 3.0 daemon threads. I'll keep that in mind for when Python 3.0 finally introduces general 2.7 compatibility. So the next best idea is to stop all the threads:
Is there any way to kill a Thread in Python?
but the best-voted response is basically "don't do that". OK, fine. So take my example above. Blocking call to sys.stdin.read()
. How do we fix that? They say use select()
:
Read file with timeout in Python
Hold on though. Select only works with file descriptors and timeouts. What if I want to receive other inputs from programs and/or libraries that aren't using file descriptors to produce data? So I have to create in-memory pipes or something?? This is getting ridiculous fast.
So, do I just have to keep using os.kill()
until Python 3.0 gains acceptance?
Or is there a better way?