Creator
Creator

Reputation: 161

How to read keyboard input from a background thread in python?

I have a background thread that occasionally needs keyboard input. However, the main thread also reads input from the keyboard. When I call input() the main thread gets the input. I have tried using locks, but they do not work for me.

Main process (only part of the code):

def smth(aff):
    af = aff

lock = threading.Lock()

print(lock)

Peer.setlock(lock)

while True:
    lock.acquire(blocking=True, timeout=-1)
    inp = input()
    parse(inp)
    lock.release()

Thread code:

global lock

def setlock(j):
    print("Setting lock ", j)
    global lock
    lock = j

print("Lock status: ", lock.locked())
success = lock.acquire(blocking=True, timeout=-1)
print(success)
print("You are recieving a file, type y to confirm saving:")
print(lock)

if input() == "y":
    path = ""
    print("Input path:")
    path = input()
    if os.path.isfile(path):
        print("File already exists. Type y to confirm:")
        if not input()=="y":
            return
    handle = open(path, "wb")
    filewriters[transferID] = filewg(handle, numberOfPackets)
    filewriters[transferID].send(None)
lock.release()
print(lock)

The entire code resides here.

I just wrote another minimal example, and locks seem to work here: import threading

lock = threading.Lock()

def th():
    while True:
        lock.acquire(blocking=True, timeout=-1)
        print("Thread prints ", input())
        lock.release()

tic = threading.Thread(target=th)

tic.start()

while True:
    lock.acquire(blocking=True, timeout=-1)
    print("Main prints ", input())
    lock.release()

Upvotes: 2

Views: 2367

Answers (1)

Bill Gribble
Bill Gribble

Reputation: 1797

The immediate problem is that input() in the main thread blocks and waits for input with the lock held. So no matter when your background thread tries to get input, the main thread is already holding the lock and waiting for input, and the first input goes to the main thread.

After that, the main thread calls release() and then acquire() again immediately. Unfortunately threading.Lock makes no guarantees about fairness.. even if the background thread was waiting in acquire() it's possible that the main thread's subsequent acquire() will succeed first, "jumping the line" on the background thread.

Step back and look at what you are trying to do in the "big picture". You have one resource (the terminal input stream) that you are trying to direct to two different locations depending on the program execution context. I would think about a model where just one thread does the input() but you look at global state to see what to do with it after that.

Upvotes: 2

Related Questions