简体   繁体   中英

exit program stuck on sys.stdin.readline

I have a thread waiting on input, but in the event that no input is provided, I need to exit the program. How can i exit the program? in this example the exit should be triggered by keyboard ctrl+c however I would also like to do this without interaction ie via a timeout or other event.

import threading
import signal
import sys
import time

shutdown = False

def shutdownHook(sigNum, currentStackFrame):
        global shutdown
        print('shutdown')
        shutdown = True

def readInput():
        print('readInput')
        print(sys.stdin.readline())
        print('done reading input')

if __name__ == '__main__':
        signal.signal(signal.SIGINT, shutdownHook)
        signal.signal(signal.SIGTERM, shutdownHook)

        inputThread = threading.Thread(name='input', target=readInput)
        inputThread.start()
        print('started input')

        while not shutdown:
                time.sleep(1)
                print('waiting ' + str(shutdown))
        print('current thread' + str(threading.current_thread()))
        print('end of program ' + str(shutdown))
        sys.exit(0)

You may use signal.alarm() to send a SIGALRM to your program after a certain amount of time (define here in second):

if __name__ == '__main__':
    # Set the signal handler and a 5-second alarm
    signal.signal(signal.SIGALRM, shutdownHook)
    signal.alarm(5)

Here is the complete working example from the documentation:

Here is a minimal example program. It uses the alarm() function to limit the time spent waiting to open a file; this is useful if the file is for a serial device that may not be turned on, which would normally cause the os.open() to hang indefinitely. The solution is to set a 5-second alarm before opening the file; if the operation takes too long, the alarm signal will be sent, and the handler raises an exception.

import signal, os

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    raise OSError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm

As for why your program is not quitting is because quoted the doc

Python signal handlers are always executed in the main Python thread, even if the signal was received in another thread. This means that signals can't be used as a means of inter-thread communication. You can use the synchronization primitives from the threading module instead. Besides, only the main thread is allowed to set a new signal handler.

That means your thread cannot receive no signals the way you design the program. In fact if you try to set a signal in your thread you will receive a ValueError :

ValueError: signal only works in main thread

That's why your program keeps turning after receiving a SIGTERM . Because the thread did not received the signal.

See here: Kill python thread using os for alternative solution.

Make the thread as Deamon thread, this way it will also shutdown when main thread is exited.

inputThread = threading.Thread(name='input', target=readInput)
inputThread.setDaemon(True) # add this line
inputThread.start()

Also you can add a time lapse for no activity within specified period.

time_limit_for_shutdown_in_secs = 10 
secs = 0
while not shutdown:
        if secs > time_limit_for_shutdown_in_secs: break
        time.sleep(1)
        print('waiting ' + str(shutdown))
        secs += 1

print('current thread' + str(threading.current_thread()))
print('end of program ' + str(shutdown))
sys.exit(0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM