如何在Windows中使用subprocess Popen.send_signal(CTRL_C_EVENT)获得预期结果?
在Windows的Python 2.7中,根据文档,你可以发送一个CTRL_C_EVENT信号,具体可以参考Python 2.7的Subprocess Popen.send_signal文档。不过,当我尝试这样做时,子进程并没有收到我期待的键盘中断。
这是父进程的示例代码:
# FILE : parentProcess.py
import subprocess
import time
import signal
CREATE_NEW_PROCESS_GROUP = 512
process = subprocess.Popen(['python', '-u', 'childProcess.py'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
creationflags=CREATE_NEW_PROCESS_GROUP)
print "pid = ", process.pid
index = 0
maxLoops = 15
while index < maxLoops:
index += 1
# Send one message every 0.5 seconds
time.sleep(0.5)
# Send data to the subprocess
process.stdin.write('Bar\n')
# Read data from the subprocess
temp = process.stdout.readline()
print temp,
if (index == 10):
# Send Keyboard Interrupt
process.send_signal(signal.CTRL_C_EVENT)
这是子进程的示例代码:
# FILE : childProcess.py
import sys
while True:
try:
# Get data from main process
temp = sys.stdin.readline()
# Write data out
print 'Foo ' + temp,
except KeyboardInterrupt:
print "KeyboardInterrupt"
如果我运行parentProcess.py这个文件,我希望看到“Foo Bar”打印十次,然后出现一个“KeyboardInterrupt”,接着再打印“Foo Bar”四次,但实际上我得到了“Foo Bar”打印了十五次。
有没有办法让CTRL_C_EVENT像Linux中的SIGINT那样,表现得像一个键盘中断呢?
在阅读了一些资料后,我发现了一些信息,似乎和Python文档中关于CTRL_C_EVENT的内容相矛盾,特别是它提到:
CTRL_C_EVENT 0 生成一个CTRL+C信号。这个信号不能为进程组生成。
以下网站提供了关于创建标志的更多信息:进程创建标志。
2 个回答
尝试使用
win32api.GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgroupid)
或者
win32api.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pgroupid)
参考资料:
http://docs.activestate.com/activepython/2.5/pywin3/win32process_CREATE_NEW_PROCESS_GROUP.html
http://msdn.microsoft.com/en-us/library/ms683155%28v=vs.85%29.aspx
了解关于 dwProcessGroupId 的信息,组 ID 应该和进程 ID 是一样的。
这个子进程处理信号的方法在我使用Python 2.7.2的Linux和Windows 2008上都能正常工作,不过它是用Ctrl-Break而不是Ctrl-C来处理的。关于进程组和Ctrl-C的说明,可以参考这个链接。
下面是catcher.py的代码:
import os
import signal
import sys
import time
def signal_handler(signal, frame):
print 'catcher: signal %d received!' % signal
raise Exception('catcher: i am done')
if hasattr(os.sys, 'winver'):
signal.signal(signal.SIGBREAK, signal_handler)
else:
signal.signal(signal.SIGTERM, signal_handler)
print 'catcher: started'
try:
while(True):
print 'catcher: sleeping...'
time.sleep(1)
except Exception as ex:
print ex
sys.exit(0)
下面是thrower.py的代码:
import signal
import subprocess
import time
import os
args = [
'python',
'catcher.py',
]
print 'thrower: starting catcher'
if hasattr(os.sys, 'winver'):
process = subprocess.Popen(args, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
else:
process = subprocess.Popen(args)
print 'thrower: waiting a couple of seconds for catcher to start...'
time.sleep(2)
print 'thrower: sending signal to catch'
if hasattr(os.sys, 'winver'):
os.kill(process.pid, signal.CTRL_BREAK_EVENT)
else:
process.send_signal(signal.SIGTERM)
print 'thrower: i am done'