clstaudt
clstaudt

Reputation: 22438

How to interrupt native extension code without killing the interpreter?

I am working on a project which combines high-performance algorithms written in C++ with a Python interface. C++ classes and functions are wrapped and exposed to Python via the Cython compiler.

Suppose I call a long running native function from the Python interpreter (my preferred one is IPython). Is it somehow possible to interrupt or abort the execution of that code without killing the interpreter?

Upvotes: 3

Views: 1056

Answers (3)

0 _
0 _

Reputation: 11474

The package cysignals addresses this issue. See this answer.

Upvotes: 0

newling
newling

Reputation: 634

Here is a possible implementation using multiprocessing as suggested by Ricardo C.,

import multiprocessing as mpr
def dangerwrap(f):
  """
  I assume f is, or eventually calls, 
  some external function, like cython wrapped C/C++.
  Also assuming that f returns an
  object and takes no parameters
  """
  event  = mpr.Event()
  q = mpr.Queue()

  def signalling_f():
    q.put(f())
    event.set()

  f_process = mpr.Process(target = signalling_f)
  f_process.start()
  try:
    event.wait()

  except KeyboardInterrupt:
    f_process.terminate()
    f_process.join()
    print "Caught in dangerwrap"
    return None


  print "Exiting normally"
  return q.get()

Now instead of,

X = f()

which will not respond to keyboard interrupts, calling

X = dangerwrap(f)

will stop gracefully with a keyboard interrupt.

Upvotes: 4

Ricardo Cárdenes
Ricardo Cárdenes

Reputation: 9172

Ok, I'm assuming here that you're trying to run some piece of optimized code that may run into trouble (eg. running for longer than expected) and then you'd need to kill it.

My understanding is that stopping the running code is just not possible without killing the interpreter, as the C/C++ code will be running out of Python's virtual machine control. So, one option would be to use the standard multiprocessing module to run the code in a separate process.

Doing so would allow you to pass data back and forth seamlessly and it would add the possibility to kill the new process using any standard means, eg. Process.terminate, os.kill... from the parent process; or any command line/graphical tool that your OS provides.

Upvotes: 2

Related Questions