Search code examples
pythonlinuxmultithreadingexceptionnonblocking

How to continue code after thread? Confused about the flow of this code


Sorry I'm new to programming, and don't really understand how this Thread thing works. My goal was for this input to be timed, and I found some code that does that. However, I'm confused about the structure of this Thread because if you are "too slow", the program never continues on to print "checkpoint" as desired. It just sort of... freezes... Why is it getting stuck?

import time
from threading import Thread

answer = None

def check():
    # waits for user input for 3 seconds
    for i in range(3):
        time.sleep(1)
        if answer != None:
            return
    print('too slow')

Thread(target = check).start()

answer = input("Input something: ")

print('checkpoint')

One thing I tried is:

t = Thread(target = check)
t.start()
answer = input("Input something: ")
# also tried t.join()
if t.is_alive:
    print('hi')

I tried to solve this program by trying to raise and catch an exception. However, I couldn't catch the exception. How do I catch it? (Or is there another solution to the problem I am having?)

import time
from threading import Thread

answer = None

def check():
    # waits for user input for 3 seconds
    for i in range(3):
        time.sleep(1)
        if answer != None:
            return
    print('too slow')
    # was hoping to catch this as an exception
    raise TimeoutError

# starts new thread
Thread(target = check).start()

# prompts user for an input
answer = input("Input something: ")

print('checkpoint')

What's good: When you type something into the input prompt within 3 seconds, it prints "checkpoint" and continues on with code.

What's bad: If you take "too long", the program prints "too slow!" as expected, BUT then it stops executing code and just sort of... freezes. So to try to fix this, I was hoping to raise a Timeout Error and then catch it, but I don't know how to catch it. This didn't catch the error:

try:
    Thread(target = check).start()
except:
    pass

This didn't either:

try:
    answer = input("Input something: ")
except:
    pass

Could I get some help? Thank you!

Edit: Forgot to mention that I am using linux so a lot of the solutions for my application did not work for me like msvcrt or keyboard. And modules that do work for Linux seem not to be "non-blocking."


Solution

  • You should think of the two threads as two separate programs, but sharing the same variables.

    Thread 1 consists of everything that isn't indented in your code. It launches a thread, then it waits for user input, then it prints "checkpoint". Then it's done.

    Thread 2 consists of the function check. It checks to see if the variable isn't None. If that happens it's done. If that doesn't happen in three seconds, it prints "too slow" and now it's done.

    Neither thread "knows" what the other one is doing, except they share one variable, answer.

    The program as a whole will exit when all its threads are finished.

    That's it. That's what you've written. So if you type something, the program exits because Thread 1 will always exit after you type something. Thread 2 exits once it sees the variable isn't None.

    If you don't type anything, Thread 1 will just sit there and wait for you, forever. That's how the input function works. Thread 2 will exit after 3 seconds or less, but that doesn't affect Thread 1.

    You can't throw an Exception from one Thread to another. So you can't throw an exception from Thread 2 and have Thread 1 handle it.

    Have you tried typing something AFTER the message "too slow" appears? When you do, Thread 1 (and therefore your program) will exit.

    The bottom line is that you can't use the input function in cases like this, because that function blocks the flow of its thread until the user types something. There is nothing any other thread can do to make it continue.