【问题标题】:Python, cannot interrupt subprocess with Ctrl-C in windowsPython,无法在 Windows 中使用 Ctrl-C 中断子进程
【发布时间】:2016-06-23 09:48:12
【问题描述】:

我有一些Python代码可以用子进程调用外部可执行程序,并将输出实时读回GUI,我希望随时用Ctrl-C中断外部二进制文件,但似乎不起作用。

我在 Windows 上工作。我希望在按下 Ctrl-C 时停止子进程。

这是我的代码:

class binary_run():
    def __init__ (self, tcl_file_name, cmd_str, output_ctrl, exe_cwd):

        self.some_exe = "E:\\some.exe"
        self.cmd = cmd = self.some_exe + cmd_str
        self.output_ctrl = output_ctrl


    def PrintOutputInRealTime(self):
        #The following two lines are to make sure the console window is hidden
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

        #Start the subprocess
        process = subprocess.Popen(self.cmd, startupinfo=startupinfo, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

        while True:
            try:
                output = process.stdout.readline()
                if output == '' and process.poll() is not None:
                    break
                if output:
                    self.output_ctrl.write(output)
            except KeyboardInterrupt: #Never comes here
                process.terminate()
        process.terminate()

    def run_binary(self):
        worker = Thread(target=self.PrintOutputInRealTime)
        worker.start()

【问题讨论】:

    标签: python subprocess copy-paste interrupt


    【解决方案1】:

    在使用线程运行可执行文件并读取其数据的某个时候,我自己也遇到了类似的情况。我使用下面的方法来解决这个问题

    import threading
    import subprocess
    import time
    
    class binary_run():
        def __init__ (self):
            self.some_exe = "notepad.exe"
    
        def PrintOutputInRealTime(self):
            self.process = subprocess.Popen(self.some_exe,stdin=subprocess.PIPE, stdout=subprocess.PIPE)
            while True:
                try:
                    output = self.process.stdout.readline()
                    if output == '' and self.process.poll() is not None:
                        break
                    if output:
                        self.output_ctrl.write(output)
                except:
                    pass
    
        def KillProcess(self):
            self.process.terminate()
    
    if __name__ == "__main__":
        x = binary_run()
        worker = threading.Thread(target=x.PrintOutputInRealTime)
        worker.start()
        try:
            while worker.isAlive():
                time.sleep(0.5)
        except KeyboardInterrupt:
                print "Got Interrupt"
                x.KillProcess()
    

    【讨论】:

    • 另一种方法是为 Ctrl+C 设置自定义处理程序:signal.signal(signal.SIGINT, lambda *a: x.KillProcess())(在主线程中)。
    • @sarbjit 非常感谢您的帮助。不知何故,它不适用于我的情况。我调用了外部可执行程序,但控制台是隐藏的,我通过管道将控制台的输出打印到我的 GUI。使用 time.sleep(0.5),主线程被阻塞,我再也看不到输出了。在打印可执行程序的输出时,我需要 GUI 仍在工作。
    • @J.F.塞巴斯蒂安 谢谢!如果显示了我的外部可执行程序的控制台窗口,则 Ctrl+C 可以工作,但我需要隐藏控制台窗口,这就是它无法接收 SIGINT 的原因。
    • @Y.Yuan : 如果没有控制台(在 Ctrl+C 上生成 SIGINT);您应该使用您的 GUI 工具包提供的任何方式显式绑定键,example
    【解决方案2】:

    感谢@J.F.Sebastian,我没有使用KeyboardInterrupt,而是将按键(Ctrl+Delete)绑定到我的GUI,如果按键按下,子进程将终止,它的工作方式如下:

    class binary_run():
        def __init__ (self, tcl_file_name, cmd_str, output_ctrl, exe_cwd):
    
            self.some_exe = "E:\\some.exe"
            self.cmd = self.some_exe + cmd_str
            self.output_ctrl = output_ctrl
    
            self.output_ctrl.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
    
        def PrintOutputInRealTime(self):
            #The following two lines are to make sure the console window is hidden
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    
            #Start the subprocess
            self.process = subprocess.Popen(self.cmd, startupinfo=startupinfo, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    
            while True:
                try:
                    #output = process.stdout.readline()
                    output = self.process.stdout.readline()
                    if output == '' and self.process.poll() is not None:
                        break
                    if output:
                        self.output_ctrl.write(output)
                except KeyboardInterrupt:
                    self.process.terminate()
    
            self.process.terminate()
    
        def OnKeyDown(self, event):
            controlDown = event.ControlDown()
            keycode = event.GetKeyCode()
    
            if (controlDown and keycode == wx.WXK_DELETE):
                wx.MessageBox('Binary got interrupted!', 'INFO', wx.OK | wx.ICON_INFORMATION)
                self.process.terminate()
    
        def run_binary(self):
            worker = Thread(target=self.PrintOutputInRealTime)
            worker.start()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      • 1970-01-01
      • 2017-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多