Reputation: 81
Reading through posts of similar questions I strongly suspect there is no way to do what I'm trying to do but figured I'd ask. I have a program using python3 that is designed to run headless, receiving commands from remote users that have logged in. One of the commands of course is a shutdown so that the program can be ended cleanly. This section is working correctly.
However while working on this I realized an option to be able to enter commands directly, without a remote connection, would be useful in the event something unusual happened to prevent remote access. I added a local_control function that runs in it's own thread so that it doesn't interfere with the main loop. This works great for all commands except for the shutdown command.
I have a variable that both loops monitor so that they can end when the shutdown command is sent. Sending the shutdown command from within local_control works fine because the loop ends before getting back to input(). however when sending the shutdown command remotely the program doesn't end until someone presses the enter key locally because that loop remains stuck at input(). As soon as enter is pressed the program continues, successfully breaks the loop and continues with the shutdown as normal. Below is an example of my code.
import threading
self.runserver = True
def local_control(): #system to control server without remote access
while self.runserver:
raw_input = input()
if raw_input == "shutdown":
self.runserver = False
mythread = threading.Thread(target=local_control)
mythread.start()
while self.runserver:
some_input = get_remote_input() #getting command from remote user
if some_input == "shutdown":
self.runserver = False
sys.exit(0) #server is shutdown cleanly
Because the program runs primarily headless GUI options such as pygame aren't an option. Other solutions I've found online involve libraries that are not cross-platform such as msvcrt, termios, and curses. Although it's not as clean an option I'd settle for simply killing the thread to end it if I could however there is no way to do that as well. So is there a cross-platform, non-GUI option to have a non-blocking input? Or is there another way to break a blocked loop from another thread?
Upvotes: 0
Views: 419
Reputation: 1837
Not a portable solution, but in *nix, you might be able send yourself an interrupt signal from the local_control function to break the blocking input()
. You'll need the pthread ID (pthread_self
and save it somewhere readable from local_control
) for the network control thread so you can call pthread_kill
.
Upvotes: 1
Reputation: 16485
Your network-IO thread is blocking the processing of commands while waiting for remote commands, so it will only evaluate the state of runserver
after get_remote_input()
returns (and it's command is processed).
You will need three threads:
local_control()
, sending commands to the processing thread.get_remote_input()
, also sending commands to the processing thread.A queue will probably be helpful here, since you need to avoid the race condition caused by unsynchronized access as currently present with regards to runserver
.
Upvotes: 1