Mohamed Ali Touir
Mohamed Ali Touir

Reputation: 35

Separate input and print threads?

I was just wandering how to print text while waiting for the users input. Like for example if we were in a chat app, we have an input() so that the user could send messages and print() when receiving messages. It needs to be simultaneous. I tried to use threads but it always stops at a thread.

Example:

def receive(client):
    threadName = client.getThreadName()
    while not client.isStopThread():
        time.sleep(1)
        print('test')
        while (client.isThereMessage()):
            print('[' + threadName + ']: ' + client.getMessage())

and for the main program

client.startThread(thread.uid)
receiveThread = Thread(target = receive(client))
receiveThread.deamon = True
receiveThread.start()

while True:
    toSendMessage = input('[' + client.fetchThreadInfo(client.uid)[client.uid].name + ']: ')
    client.sendMessage(toSendMessage, thread_id=thread.uid, thread_type=thread.type)

Upvotes: 2

Views: 2564

Answers (1)

bnaecker
bnaecker

Reputation: 6430

You're calling the Thread class constructor incorrectly. The signature is:

threading.Thread(target=None, args=(), kwargs={})

The target is the function object itself, i.e., receive, not receive(client). You're now calling the receive function with client as the input, and then passing the return value of that function (which appears to be None) as the target keyword-argument to the Thread constructor. If the receive function loops indefinitely, then the code will definitely stall in the Thread constructor.

You should instead call the Thread constructor like so:

receiveThread = Thread(target=receive, args=(client,))

Also, in general, you don't need threading to both print something and wait for input. You can instead do what is called synchronous I/O multiplexing, which means performing I/O on multiple objects at the same time, but from a single thread. The idea is to wait for notification from the OS when one or more objects are available for either writing or reading (or both). Look at the select or selectors modules for more information.

Here is a simple example. It just waits for up to one second for input from the user. If input is received, it just echos it back, and if none is received, it prints Nothing new.

import sys
import select
timeout = 1.0
while True:
    rlist, _ = select.select([sys.stdin], [], [], timeout)
    if len(rlist):
        print(sys.stdin.readline())
    else:
        print('Nothing new')

You could adapt this to wait for both user input and for a new message that you want to print to the user's console.

Upvotes: 1

Related Questions