如何使用Swig中止Python脚本调用C函数?

时间:2012-08-27 16:05:38

标签: python c swig abort

我在尝试中止Python脚本时遇到问题,例如:

#!/usr/bin/python

import hello

hello.draw()

exit()

其中draw()是C函数。在这个函数中有一个循环来打印一些文本。我试过CTRL-C来突破它但它不起作用。 重要的是C代码无法修改!

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

我汇总了一个如何做到这一点的例子。它允许扩充功能并从中逃脱而无需修改它。例如,给定函数foo(在test.h中为测试内联):

void foo() {
  while(1); // never returns
}

您可以使用信号和siglongjmp来玩游戏。但应注意you need to be very careful以确保您只在foo内调用async safe个函数,或者在任何不安全的调用之后屏蔽信号并在屏蔽后取消屏蔽它们。

然后我们可以包装该函数并使用%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之后处理信号,这整齐地排除了整个异步安全问题。

答案 1 :(得分:0)

您需要为C函数提供一个中止它的方法 - 例如,它可以在其绘制循环中轮询全局状态标志。

答案 2 :(得分:0)

另一种可能性是停止该过程,然后终止它。在bash命令行(Linux / MacOS)中,如下所示:

假设您启动脚本...

$ python3 example.py

...然后键入 control + Z 停止该过程。在方括号中查找数字,在这种情况下为1

[1]+  Stopped                 python3 example.py

现在,您可以使用kill命令,然后在方括号中显示数字来终止该进程。

$ kill %1
[1]+  Terminated: 15          python3 example.py