用键盘中断终止子进程 我使用Python调用子进程模块的C++程序。由于程序运行需要一些时间,我希望能够使用Ctrl+C终止它。我在StackOverflow上看到了一些关于这方面的问题,但没有一个解决方案适合我
我希望子进程在键盘中断时终止。这是我的代码(类似于其他问题中的建议): 但是,如果我运行这个,代码将挂起,等待进程结束,并且从不注册键盘中断。我也尝试过以下方法:用键盘中断终止子进程 我使用Python调用子进程模块的C++程序。由于程序运行需要一些时间,我希望能够使用Ctrl+C终止它。我在StackOverflow上看到了一些关于这方面的问题,但没有一个解决方案适合我,python,windows,subprocess,interrupt,terminate,Python,Windows,Subprocess,Interrupt,Terminate,我希望子进程在键盘中断时终止。这是我的代码(类似于其他问题中的建议): 但是,如果我运行这个,代码将挂起,等待进程结束,并且从不注册键盘中断。我也尝试过以下方法: import subprocess import time binary_path = '/path/to/binary' args = 'arguments' # arbitrary call_str = '{} {}'.format(binary_path, args) proc = subprocess.Popen(cal
import subprocess
import time
binary_path = '/path/to/binary'
args = 'arguments' # arbitrary
call_str = '{} {}'.format(binary_path, args)
proc = subprocess.Popen(call_str)
time.sleep(5)
proc.terminate()
这个代码段在终止程序时工作得很好,所以问题不是发送给终止程序的实际信号
如何更改代码,以便在键盘中断时终止子进程
我正在运行Python2.7和Windows7 64位。提前谢谢
我试过的一些相关问题:
我在Windows上的丑陋但成功的尝试:
import subprocess
import threading
import time
binary_path = 'notepad'
args = 'foo.txt' # arbitrary
proc = None
done = False
def s():
call_str = '{} {}'.format(binary_path, args)
global done
global proc
proc = subprocess.Popen(call_str,stdout=subprocess.PIPE)
proc.wait()
done = True
t = threading.Thread(target=s)
t.start()
try:
while not done:
time.sleep(0.1)
except KeyboardInterrupt:
print("terminated")
proc.terminate()
创建子进程运行的线程。导出proc
变量
然后在非活动循环中永远等待。按下CTRL+C时,将触发异常。进程间通信(例如:proc.wait()
)与CTRL+C处理冲突。在线程中运行时,不会出现此类问题
注意:我曾尝试使用
threading.lock()
来避免这个时间循环,但还是遇到了相同的CTRL+C ignore。我找到了一种方法来实现这一点,类似于Jean Francois关于循环的回答,但没有多个线程。关键是使用Popen.poll()确定子流程是否已完成(如果仍在运行,则返回None)
我在KeyboardInterrupt之后添加了一个额外的raise,因此除了子进程之外,Python程序也被中断
编辑:根据eryksun的评论将pass改为time.sleep(0.1)以减少CPU消耗。为什么不在主程序中捕获ctrl-c信号并使用它调用
proc.terminate()
?在Python 3中,可以使用\u winapi.WaitForMultipleObjects([proc.\u handle],False,-1)
。对于主线程,如果wait all标志为false,则此等待将自动包括Python的SIGINT
事件。在2.x中,您必须使用ctypes或PyWin32从头开始实现此功能。@eryksun感谢您的建议。有一个名为win32event的模块具有类似的函数,可以为Python 2导入,但我尝试了win32event.WaitForMultipleObjects([proc.\u handle],False,-1)
,但没有任何区别。@limi44,3.x使用由Ctrl+C的信号处理程序设置的Windows事件对象。调用\u winapi.WaitForMultipleObjects
时,此事件会自动添加到列表中。在2.x中实现此功能需要PyWin32或ctypes定义一个控制台CTRL\u事件
处理程序(例如,将ctypes回调函数传递给SetConsoleCtrlHandler
),该处理程序设置一个事件(通过CreateEvent
创建)。然后,您需要包装WaitForMultipleObjects
,将Ctrl+C事件句柄附加到列表中,并在等待之前重置事件(ResetEvent
),但仅在从主线程调用时才重置。time.sleep(.1)
是可中断的。使用它而不是pass
可以减少CPU消耗。
import subprocess
import threading
import time
binary_path = 'notepad'
args = 'foo.txt' # arbitrary
proc = None
done = False
def s():
call_str = '{} {}'.format(binary_path, args)
global done
global proc
proc = subprocess.Popen(call_str,stdout=subprocess.PIPE)
proc.wait()
done = True
t = threading.Thread(target=s)
t.start()
try:
while not done:
time.sleep(0.1)
except KeyboardInterrupt:
print("terminated")
proc.terminate()
import subprocess
import time
binary_path = '/path/to/binary'
args = 'arguments' # arbitrary
call_str = '{} {}'.format(binary_path, args)
proc = subprocess.Popen(call_str)
try:
while proc.poll() is None:
time.sleep(0.1)
except KeyboardInterrupt:
proc.terminate()
raise