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

问题描述 投票:2回答:3

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

#!/usr/bin/python

import hello

hello.draw()

exit()

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

有任何想法吗?

python c swig abort
3个回答
2
投票

我汇总了一个如何做到这一点的例子。它允许扩充功能并从中逃脱而无需修改它。例如,给定函数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之后处理信号,这整齐地排除了整个异步安全问题。


0
投票

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


0
投票

另一种可能性是停止该过程然后将其杀死。在bash命令行(Linux / MacOS)中,它看起来像这样:

假设您启动脚本......

$ python3 example.py

...然后键入control + Z来停止进程。在方括号中查找数字,在本例中为1

[1]+  Stopped                 python3 example.py

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

$ kill %1
[1]+  Terminated: 15          python3 example.py
© www.soinside.com 2019 - 2024. All rights reserved.