3

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?

clstaudt
  • 21,436
  • 45
  • 156
  • 239
  • 1
    Dynamically loading exposed C/C++ code into Python is the same (essentially) as doing it in C or C++ so, I'd say it's not possible. One of your options would be running the code in a separate process (using `multiprocessing`, for example). – Ricardo Cárdenes Feb 04 '14 at 10:59
  • @RicardoCárdenes Running it in a separate process is an option. Can you point to some resource I should look at to learn how to interrupt or abort such a process? – clstaudt Feb 04 '14 at 11:12
  • send a kill signal to the process – user3159253 Feb 04 '14 at 11:13
  • As a side comment, `Ctrl + Z` will stop the process, then use [`top -b -n 1 | grep ipython`](http://stackoverflow.com/a/7501452/1959808) to find its `pid` and `kill pid`. – 0 _ Nov 24 '15 at 01:32
  • Possible duplicate of [Cython, Python and KeyboardInterrupt ignored](https://stackoverflow.com/questions/16769870/cython-python-and-keyboardinterrupt-ignored) – 0 _ Jan 12 '18 at 02:53

3 Answers3

4

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.

newling
  • 624
  • 6
  • 10
2

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.

Ricardo Cárdenes
  • 9,004
  • 1
  • 21
  • 34
  • So in order to kill the subprocess when `Ctrl+C` is pressed, the main process would have to read the key press (not sure how) and then call e.g. `Process.terminate` on the subprocess, right? Is it also possible to interrupt and continue the subprocess? – clstaudt Feb 04 '14 at 12:31
  • When you press "Ctrl+C", the interpreter raises the `KeyboardInterrupt` exception. Then again, you *may* not need to put the C code in a separate process (not sure) if that's all you want to do. But you should test this first. – Ricardo Cárdenes Feb 04 '14 at 12:33
0

The package cysignals addresses this issue. See this answer.

0 _
  • 10,524
  • 11
  • 77
  • 109