我试图中止Python脚本时遇到问题,例如:
#!/usr/bin/python
import hello
hello.draw()
exit()
其中draw()是一个C函数。在这个函数中有一个循环来打印一些文本。我试过CTRL-C来突破它但它不起作用。重要的是C代码无法修改!
有任何想法吗?
我汇总了一个如何做到这一点的例子。它允许扩充功能并从中逃脱而无需修改它。例如,给定函数foo
(在我的测试中,它在test.h中内联):
void foo() {
while(1); // never returns
}
你可以玩信号和siglongjmp
游戏。应该注意的是,you need to be very careful确保你只能在async safe中调用foo
函数,或者在任何不安全的调用之后屏蔽信号并在它们之前取消屏蔽它们。
然后我们可以包装函数并使用%exception
注入一些额外的代码以允许信号退出函数:
%module test
%{
#include <setjmp.h>
#include <signal.h>
static sigjmp_buf timeout;
static void backout(int sig) {
siglongjmp(timeout, sig);
}
#include "test.h"
%}
%include <exception.i>
%exception {
if (!sigsetjmp(timeout, 1)) {
signal(SIGALRM,backout); // Check return?
$action
}
else {
// raise a Python exception
SWIG_exception(SWIG_RuntimeError, "Timeout in $decl");
}
}
void foo();
%exception;
这允许我们写:
import signal
import test
signal.alarm(5)
test.foo()
考虑到有关异步安全功能的警告,这可以按预期工作。我在这里使用了SIGALRM
,因为它允许我将它全部保存在一个Python文件中。如果您愿意,可以使用其他线程/进程和其他信号。
如果你将我的例子中的SIGALRM更改为SIGINT(并且显然没有提出SIGALRM)它将与Ctrl + C一起工作 - 它不是因为how the default Python signal handlers work。 Python使用的默认处理程序只是设置一个标志,并在底层调用将控制权返回给Python之后处理信号,这整齐地排除了整个异步安全问题。
您需要为C函数提供一种中止它的方法 - 例如,它可以在其绘制循环中轮询全局状态标志。
另一种可能性是停止该过程然后将其杀死。在bash
命令行(Linux / MacOS)中,它看起来像这样:
假设您启动脚本......
$ python3 example.py
...然后键入control + Z来停止进程。在方括号中查找数字,在本例中为1
。
[1]+ Stopped python3 example.py
现在,您可以使用kill
命令终止该进程,然后使用方括号中显示的数字。
$ kill %1
[1]+ Terminated: 15 python3 example.py