编程语言
首页 > 编程语言> > Cython,Python和KeyboardInterrupt被忽略了

Cython,Python和KeyboardInterrupt被忽略了

作者:互联网

有没有办法根据嵌入在Cython扩展中的循环中断(Ctrl C)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,keyboardinterrupt
来源: https://codeday.me/bug/20190926/1821964.html