Cython,Python和KeyboardInterrupt被忽略 [英] Cython, Python and KeyboardInterrupt ignored

查看:149
本文介绍了Cython,Python和KeyboardInterrupt被忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以基于Cython扩展中嵌入的循环来中断(Ctrl+C)Python脚本?

Is there a way to interrupt (Ctrl+C) a Python script based on a loop that is embedded in a Cython extension?

我有以下python脚本:

I have the following python script:

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但忽略它,并且程序一直运行到模拟结束.

This runs a loop that is part of a C++ Cython extension. Then, while pressing Ctrl+C, the KeyboardInterrupt is thrown but ignored, and the program keeps going until the end of the simulation.

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

The work around I found, is to handle the exception from within the extension by catching the SIGINT signal :

#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的软件.

Can't I make this work from Python, or at least from Cython instead ? As I am about to port my extension under Windows/MinGW, I would appreciate to have something less Linux specific.

推荐答案

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

You have to periodically check for pending signals, for example, on every Nth iteration of the simulation loop:

from cpython.exc cimport PyErr_CheckSignals

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

PyErr_CheckSignals将运行通过 signal 模块安装的信号处理程序(包括如有必要,请提高KeyboardInterrupt.

PyErr_CheckSignals will run signal handlers installed with signal module (this includes raising KeyboardInterrupt if necessary).

PyErr_CheckSignals非常快,可以经常调用它.请注意,应该从主线程调用它,因为Python在主线程中运行信号处理程序.从辅助线程调用它无效.

PyErr_CheckSignals is pretty fast, it's OK to call it often. Note that it should be called from the main thread, because Python runs signal handlers in the main thread. Calling it from worker threads has no effect.

说明

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

Since signals are delivered asynchronously at unpredictable times, it is problematic to run any meaningful code directly from the signal handler. Therefore, Python queues incoming signals. The queue is processed later as part of the interpreter loop.

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

If your code is fully compiled, interpreter loop is never executed and Python has no chance to check and run queued signal handlers.

这篇关于Cython,Python和KeyboardInterrupt被忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆