在 Windows 中使用子程序 Popen.send_signal(CTRL_C_EVENT) 时如何达到预期的结果?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5033277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 16:12:23  来源:igfitidea点击:

How to achieve desired results when using the subprocees Popen.send_signal(CTRL_C_EVENT) in Windows?

pythonwindowssubprocesspopenkeyboardinterrupt

提问by Mario

In python 2.7 in windows according to the documentation you can send a CTRL_C_EVENT (Python 2.7 Subprocess Popen.send_signal documentation).However when I tried it I did not receive the expected keyboard interrupt in the subprocess.

根据文档,在 Windows 中的 python 2.7 中,您可以发送 CTRL_C_EVENT (Python 2.7 Subprocess Popen.send_signal 文档)。但是,当我尝试它时,我没有在子进程中收到预期的键盘中断。

This is the sample code for for the parent process:

这是父进程的示例代码:

# 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)

This is the sample code for the child proceess:

这是子进程的示例代码:

# 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"

If I run the file parentProcess.py I expect to get "Foo Bar" ten times then a "KeyboardInterrupt" followed by "Foo Bar" 4 times but I get "Foo Bar" 15 times instead.

如果我运行文件 parentProcess.py,我希望得到“Foo Bar”十次,然后是“KeyboardInterrupt”,然后是“Foo Bar”4 次,但我得到“Foo Bar”15 次。

Is there a way to get the CTRL_C_EVENT to behave as a keyboard interrupt just as SIGINT behaves in Linux?

有没有办法让 CTRL_C_EVENT 像 SIGINT 在 Linux 中的行为一样充当键盘中断?

After doing some reading I found some information that seems to contradic the python documentation regarding CTRL_C_EVENT, in particular it says that

在做了一些阅读之后,我发现了一些似乎与关于 CTRL_C_EVENT 的 python 文档相矛盾的信息,特别是它说

CTRL_C_EVENT 0 Generates a CTRL+C signal. This signal cannot be generated for process groups

CTRL_C_EVENT 0 生成 CTRL+C 信号。无法为进程组生成此信号

The following site provide more inforamtion about creation flags: Process Creation Flags.

以下站点提供了有关创建标志的更多信息: 进程创建标志。

回答by Craig McDaniel

This method of signal handling by subprocesses worked for me on both Linux and Windows 2008, both using Python 2.7.2, but it uses Ctrl-Break instead of Ctrl-C. See the note about process groups and Ctrl-C in http://msdn.microsoft.com/en-us/library/ms683155%28v=vs.85%29.aspx.

这种由子进程处理信号的方法在 Linux 和 Windows 2008 上都对我有用,都使用 Python 2.7.2,但它使用 Ctrl-Break 而不是 Ctrl-C。请参阅http://msdn.microsoft.com/en-us/library/ms683155%28v=vs.85%29.aspx 中有关进程组和 Ctrl-C 的说明。

catcher.py:

捕手.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:

投掷者.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'

回答by sherpya

try with

尝试

win32api.GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgroupid)

or

或者

win32api.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pgroupid)

references:

参考:

http://docs.activestate.com/activepython/2.5/pywin3/win32process_CREATE_NEW_PROCESS_GROUP.html

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

http://msdn.microsoft.com/en-us/library/ms683155%28v=vs.85%29.aspx

read info about dwProcessGroupId, the groupid should be the same of the process id

读取有关 dwProcessGroupId 的信息,groupid 应该与进程 id 相同