【问题标题】:exit program stuck on sys.stdin.readline退出程序卡在 sys.stdin.readline
【发布时间】:2017-12-29 07:04:36
【问题描述】:

我有一个线程正在等待输入,但如果没有提供输入,我需要退出程序。我怎样才能退出程序?在这个例子中,退出应该由键盘 ctrl+c 触发,但是我也想在没有交互的情况下执行此操作,即通过超时或其他事件。

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)

【问题讨论】:

  • 你能看到done reading input 吗?
  • 我认为是线程本身的问题,让我想更多
  • ctl+c 显示“shutdown”、“waiting True”、“current thread...”、“end of program True”,但不退出。

标签: python python-3.x


【解决方案1】:

您可以在一定时间后使用signal.alarm() 向您的程序发送SIGALRM(此处定义为秒):

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

这是文档中的complete working example

这是一个最小的示例程序。它使用 alarm() 函数 限制等待打开文件的时间;如果 文件用于可能未打开的串行设备,这将 通常会导致 os.open() 无限期挂起。解决方案是 打开文件前设置5秒闹钟;如果手术需要 太长,将发送警报信号,并且处理程序会引发 例外。

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

至于你的程序为什么不退出是因为quoted the doc

Python 信号处理程序总是在 Python 主线程中执行, 即使信号是在另一个线程中收到的。这意味着 信号不能用作线程间通信的手段。你 可以使用线程模块中的同步原语 反而。此外,只允许主线程设置新的信号处理程序。

这意味着您的线程无法按照您设计程序的方式接收任何信号。事实上,如果你尝试在你的线程中设置一个信号,你会收到一个ValueError

ValueError: signal only works in main thread

这就是为什么您的程序在收到SIGTERM 后不断运行的原因。因为线程没有收到信号。

请参阅此处:Kill python thread using os 了解替代解决方案。

【讨论】:

    【解决方案2】:

    将线程设为Deamon线程,这样在主线程退出时也会关闭。

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

    您还可以添加指定时间段内没有活动的时间间隔。

    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)
    

    【讨论】:

    • 这是错误的答案,你没有回答 OP,你只是在打破循环!如果您不想被否决,请更正您的答案
    • 如果在一定时间内没有收到任何输入,则要求退出程序
    • 所以你甚至没有只运行一次代码,当你输入第一个输入时的代码库存
    • 问题不在于循环,而在于 sys.exit 没有退出,因为 stdin.readline 被阻塞了。
    • 是的,我的错,没有注意到它确实没有退出,我已经更新了我的答案,这目前正在我的工作中。
    猜你喜欢
    • 2021-11-12
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    相关资源
    最近更新 更多