python - 忽略 Cython、Python 和 KeyboardInterrupt

标签 python cython keyboardinterrupt

有没有办法中断 (Ctrl+C) 基于嵌入在 Cython 扩展中的循环的 Python 脚本?

我有以下 python 脚本:

def main():

    # Intantiate simulator
    sim = PySimulator()
    sim.Run()

if __name__ == "__main__":
    # Try to deal with Ctrl+C to abort the running simulation in terminal
    # (Doesn't work...)
    try:
        sys.exit(main())
    except (KeyboardInterrupt, SystemExit):
        print '\n! Received keyboard interrupt, quitting threads.\n'

这会运行一个循环,该循环是 C++ Cython 扩展的一部分。 然后,在按下 Ctrl+C 的同时,KeyboardInterrupt 被抛出但被忽略,程序继续运行直到模拟结束。

我发现的解决方法是通过捕获 SIGINT 信号来处理扩展中的异常:

#include <execinfo.h>
#include <signal.h>

static void handler(int sig)
{
  // Catch exceptions
  switch(sig)
  {
    case SIGABRT:
      fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr);
      break;
    case SIGFPE:
      fputs("Caught SIGFPE: arithmetic exception, such as divide by zero\n",
            stderr);
      break;
    case SIGILL:
      fputs("Caught SIGILL: illegal instruction\n", stderr);
      break;
    case SIGINT:
      fputs("Caught SIGINT: interactive attention signal, probably a ctrl+c\n",
            stderr);
      break;
    case SIGSEGV:
      fputs("Caught SIGSEGV: segfault\n", stderr);
      break;
    case SIGTERM:
    default:
      fputs("Caught SIGTERM: a termination request was sent to the program\n",
            stderr);
      break;
  }
  exit(sig);

}

然后:

signal(SIGABRT, handler);
signal(SIGFPE,  handler);
signal(SIGILL,  handler);
signal(SIGINT,  handler);
signal(SIGSEGV, handler);
signal(SIGTERM, handler);

我不能用 Python 或至少用 Cython 来完成这项工作吗?当我即将在 Windows/MinGW 下移植我的扩展时,我希望能有一些不那么特定于 Linux 的东西。

最佳答案

您必须定期检查未决信号,例如,在模拟循环的每 N 次迭代中:

from cpython.exc cimport PyErr_CheckSignals

cdef Run(self):
    while True:
        # do some work
        PyErr_CheckSignals()

PyErr_CheckSignals 将运行随 signal 安装的信号处理程序模块(这包括在必要时引发 KeyboardInterrupt)。

PyErr_CheckSignals 相当快,经常调用就可以了。请注意,它应该从主线程调用,因为 Python 在主线程中运行信号处理程序。从工作线程调用它没有任何效果。

解释

由于信号是在不可预测的时间异步传递的,因此直接从信号处理程序运行任何有意义的代码都是有问题的。因此,Python 对传入信号进行排队。该队列稍后作为解释器循环的一部分进行处理。

如果您的代码已完全编译,则永远不会执行解释器循环,Python 也没有机会检查和运行排队的信号处理程序。

关于python - 忽略 Cython、Python 和 KeyboardInterrupt,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16769870/

相关文章:

python - 如何使用 Figure(matplotlib FigureCanvasQTAgg) 绘制具有多个 yaxis 的共享 xaxis 子图?

executable - 如何检查 autoconf 中可执行文件的完整路径是否正确

teamcity - 为什么 Teamcity 会发送键盘中断来终止我的构建?

python - 线程忽略 KeyboardInterrupt 异常

python - Django 用户密码未针对自定义用户进行哈希处理

python - 我可以使用生成的 swig 代码将 C++ 对象转换为 PyObject 吗?

python - 根据字典检查数据帧值(作为键,值元组)的矢量化方法?

python - 使用 LU 分解求逆矩阵

python - 使用 PyArray_NewFromDescr 存储数据