views:

141

answers:

1

Maybe i cant do what i want? I want to have 1 thread do w/e it wants and a 2nd thread to recv user input to set the quit flag. using this code i want to enter q anytime to quit or have it timeout after printing hey 6 times

import sys
import threading
import time

class MyThread ( threading.Thread ):
    def run (s):
        try:
            s.wantQuit = 0
            while(not s.wantQuit):
                print "want input"
                button = raw_input()
                if button == "q":
                    s.wantQuit=1
        except KeyboardInterrupt:
            s.wantQuit = 1
            print "abort with KeyboardInterrupt"
        print "done mythread"

myThread = MyThread ()
myThread.start()

a=5
while not myThread.wantQuit:
    print "hey"
    if (a == 0):
        break;
    a = a-1;
    time.sleep(1)
myThread.wantQuit=1
print "main thread done"

what happens is instead of two threads i have the main one printing hey 4/6 times, then a dialog poping up asking for my input and the app being locked up until i enter it. WTF?!

want input
hey
hey
hey
hey
abort with KeyboardInterrupt
done mythread
main thread done

i am using PyScripter (it has debugging), i also tried pydle which doesnt seem to allow me to enter input and locks up eventually after running it once.

+2  A: 

The problem here is that raw_input waits for an enter to flush the input stream; check out its documentation. PyScripter is probably seeing that the program is waiting for an input and giving you an input box (don't know for sure, never used it.)

The program works exactly as I expect it to from the command line; the secondary thread blocks on the raw_input until I hit "q[enter]", at which point the program ends.

It is not, AFAICS, easy to check and see if a character is available in the input stream before blocking on a read call. You probably should check out this thread on how to read a character in a blocking fashion without requiring an [enter], and then this post on the challenge of reading a character without blocking at all.

You can possibly use a combination of msvcrt.kbhit on windows and this recipe from the python FAQ to get the q character without requiring a keypress, but I'll leave it as an exercise to the reader.

Addendum: One thing you could do would be to use the select library to set a timeout on reads from the keyboard, which will make your program act more like you expect:

import sys
import threading
import time
import select

def timeout_read(n_chars):
  r, _, _ = select.select([sys.stdin], [], [], 1)
  return r[0].read(n_chars) if r else ""

class MyThread (threading.Thread):
    def run (self):
        try:
            self.wantQuit = 0
            while not self.wantQuit:
                print "want input"
                button = timeout_read(1)
                if button == "q":
                    self.wantQuit=1
        except KeyboardInterrupt:
            self.wantQuit = 1
            print "abort with KeyboardInterrupt"
        print "done mythread"

myThread = MyThread ()
myThread.start()

a=5
while not myThread.wantQuit:
    print "hey"
    if (a == 0):
        break;
    a = a-1;
    time.sleep(1)
myThread.wantQuit=1
print "main thread done"

Note that you will still need to press "q[enter]" with this solution.

llimllib