0

I am writing a program with an infinite while loop that runs a function which takes input from the user and then prints to the console. I would like to be able to do something along the lines of having a separate piece of code that continually checks the time as a background process and at a certain time, prints a message to the console and asks whether you'd like to quit the program or continue the while loop. I assume I'd need multithreading or something along the lines of that.

def main():
    while True:
        x = input("Write Something: ")
        print(x)

main()
4
  • 1
    Could you clarify your question and include any code you currently have? Commented Sep 17, 2013 at 4:36
  • Why can't you do that inside the while loop? With multithreading you will have to deal with interleaved output. Commented Sep 17, 2013 at 4:36
  • The program is kinda lengthy so I've taken it down to the basics. What I'd like is to somehow pause the main function, 'inject' a print statment at a given time, and then ask the user whether they would like to continue with the main() function or quit the program Commented Sep 17, 2013 at 4:43
  • 1
    I can't check the time inside the main() while loop. Suppose the user got up right as the specified time was reached, the code would never execute because it would still be waiting on user input before it looped again. I need a separate process independent of the main() function that can interrupt when a certain time is reached Commented Sep 17, 2013 at 4:51

2 Answers 2

2

Threads are good for this, and the background thread will spend most of its time sleeping. Here's something you can start with. You'll have lots of problems eventually - comes with the territory ;-)

import threading

timetoquit = False
iolock = threading.Lock()

class Watcher(threading.Thread):
    def __init__(self, timeout):
        threading.Thread.__init__(self)
        self.timeout = timeout
        self.waiter = threading.Event()

    def run(self):
        global timetoquit
        while not timetoquit:
            self.waiter.wait(self.timeout)
            if timetoquit:
                return
            with iolock:
                i = raw_input("want to quit? ")
            if i.startswith("y") or i.startswith("Y"):
                timetoquit = True
            self.waiter.clear()

    # Unused in this example, but you may want it someday ;-)
    def cancel(self):
        global timetoquit
        timetoquit = True
        self.waiter.set()

# this Watcher will ask every 10 seconds
watch = Watcher(10)
watch.start()

while not timetoquit:
    # do stuff
    # put console interaction in `with iolock` to
    #   prevent the main program and the thread from
    #   messing with the console at the same time
    with iolock:
        if not timetoquit:
            whatever = raw_input("enter something ")
    # do stuff
Sign up to request clarification or add additional context in comments.

12 Comments

Thank you for the prompt reply! I apologize that I don't fully understand all of your code. I'm not the best with classes yet. I'm pretty sure from your notes, however, that it's supposed to prompt me after 10 seconds to quit or contine. The 'enter something' part runs fine but it never does anything other than that.
The thread should ask you want to quit? every 10 seconds. Don't run it in (for example) Idle. "Development environments" very often don't play well with threads or with multiprocessing. Run it from a command shell. BTW, I tested it with Python 2.7.5, but that shouldn't matter.
Also, you have to respond to the "enter something" prompts. The whole purpose of iolock is to stop the thread and the main program from messing with the console input/output at the same time. That would be a real mess ;-) Just keep hitting ENTER.
But it's not a video game either - LOL ;-) I mean if you keep hitting ENTER quickly, the thread won't get a chance to run. Wait a second or two.
I think a GIL battle is going on. When I run this code on Ubuntu, the "want to quit?" message is virtually never printed (unless I press and hold the Enter key to make it autorepeat). I think the reason for this has to do with the main thread's while-loop being so tight that the OS's thread scheduler is virtually always letting the main thread get to with iolock before the Watcher thread getting to with iolock. I was able to avoid the problem by putting time.sleep(0) inside the main thread's while-loop.
|
1

Here is an attempt using Tim Peters' suggestion to use threading.Timer:

import threading

check_done = False
def are_we_done_yet():
    global check_done
    print("quit now?")
    check_done = True
    t = threading.Timer(2.0, are_we_done_yet)
    t.daemon = True
    t.start()

t = threading.Timer(2.0, are_we_done_yet)
t.daemon = True
t.start()

while True:
    response = raw_input('>>> ')
    if check_done:
        if response.lower().startswith('y'): break
        check_done = False

One problem with the code above is that there is no way to distinguish input that the user intended for the >>> prompt from the user's response to the question quit now?.

If the user happened to be typing a sentence beginning with a y when the quit now? question pops up, then the user might unintentionally cause the program to quit.

So a cleaner solution might be to use a GUI:

import Tkinter as tk
import tkMessageBox
def are_we_done_yet():
    if tkMessageBox.askyesno(title="Quit", message="Quit now?",
                             default=tkMessageBox.NO):
        root.quit()
    root.after(2000, are_we_done_yet)

root = tk.Tk()
root.geometry('300x200')
entry = tk.Text(root)
entry.pack()
entry.focus()
root.after(2000, are_we_done_yet)
root.mainloop()

1 Comment

I'm not yet clear on what the OP wants to do, exactly. Using a different window (like your second approach) is best if he really wants to do what we think he wants ;-) But what a horrid UI :-( If a user wants to quit, they can just stop the program - prompting them over & over would sure be annoying to me ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.