gpt4 book ai didi

python - 如何从单元测试模拟终端 CTRL + C 事件?

转载 作者:行者123 更新时间:2023-11-28 21:50:21 27 4
gpt4 key购买 nike

我有一个忽略 multiprocessing.ProcessSIGINT 子类:

# inside the run method
signal.signal(signal.SIGINT, signal.SIG_IGN)

我不希望这个过程在按下 CTRL + C 时终止,所以我试图通过发送 SIGINT 信号在我的单元测试中模拟这个终端事件到此进程 ID:

os.kill(PID, signal.SIGINT)

但即使不忽略这个信号,进程也不会终止,所以这个测试是无用的,我从其他问题中发现,在 CTRL + C 事件中,终端将 SIGINT 发送到进程组 ID,但我不能这样做,因为它也会终止单元测试进程。

那么为什么进程在从 SIGINT 接收到 os.kill 时没有终止?我应该以另一种方式这样做吗?

最佳答案

子进程应在收到 SIGINT 后终止,除非它忽略该信号或安装了自己的处理程序。如果您没有明确忽略子项中的 SIGINT,那么 SIGINT 可能在父项中被忽略,因此在子项中也可能被忽略,因为信号处置是继承的。

但是,我无法重现您的问题,事实上,我发现了相反的问题:子进程终止,无论其信号处置如何。

如果信号发送得太快,在子进程忽略 SIGINT 之前(在其 run() 方法中),它将被终止。下面是一些演示问题的代码:

import os, time, signal
from multiprocessing import Process

class P(Process):
def run(self):
signal.signal(signal.SIGINT, signal.SIG_IGN)
return super(P, self).run()

def f():
print 'Child sleeping...'
time.sleep(10)
print 'Child done'

p = P(target=f)
p.start()
print 'Child started with PID', p.pid

print 'Killing child'
os.kill(p.pid, signal.SIGINT)
print 'Joining child'
p.join()

输出

Child started with PID 1515Killing childJoining childTraceback (most recent call last):  File "p1.py", line 15, in     p.start()      File "/usr/lib64/python2.7/multiprocessing/process.py", line 130, in start    self._popen = Popen(self)  File "/usr/lib64/python2.7/multiprocessing/forking.py", line 126, in __init__    code = process_obj._bootstrap()  File "/usr/lib64/python2.7/multiprocessing/process.py", line 242, in _bootstrap    from . import utilKeyboardInterrupt

Adding a small delay with time.sleep(0.1) in the parent just before sending the SIGINT signal to the child will fix the problem. This will give the child enough time to execute the run() method in which SIGINT is ignored. Now the signal will be ignored by the child:

Child started with PID 1589Killing childChild sleeping...Joining childChild done

An alternative that requires no delays nor custom run() method is to set the parent to ignore SIGINT, start the child, then restore the parent's original SIGINT handler. Because the signal disposition is inherited, the child will ignore SIGINT from the moment it starts:

import os, time, signal
from multiprocessing import Process

def f():
print 'Child sleeping...'
time.sleep(10)
print 'Child done'

p = Process(target=f)
old_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN)
p.start()
signal.signal(signal.SIGINT, old_sigint) # restore parent's handler
print 'Child started with PID', p.pid

print 'Killing child'
os.kill(p.pid, signal.SIGINT)
print 'Joining child'
p.join()

输出

Child started with PID 1660Killing childJoining childChild sleeping...Child done

关于python - 如何从单元测试模拟终端 CTRL + C 事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32023719/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com