Is there any way to stop a running Python interpreter after a Python method was called via Boost Python from within C++?
I want to interrupt the call for 2 reasons:
My search on the web and in the Boost documentation didn't turn up anything, but on the other hand I sometimes struggle to find the right paragraph in the Boost docs...
The only "sort of idea" I got from this StackOverflow question . The idea would be to send a signal to the script, but as the interpreter runs within my C++ process, this probably not a viable option?!
I am doing the following:
const boost::filesystem::path pythonScriptPath = /* Path to the script I want to execute a function from. */
const std::string pythonFunctionName = /* Name of the Python function to call. */;
boost::python::object mainModule = boost::python::import("__main__");
boost::python::object mainNameSpace = mainModule.attr("__dict__");
boost::python::dict locals;
locals["moduleName"] = pythonScriptPath.stem().string();
locals["modulePath"] = pythonScriptPath.string();
std::stringstream importModuleStream;
importModuleStream
<< "import imp\n"
<< "newModule = imp.load_module(moduleName, open(modulePath), modulePath, ('py', 'U', imp.PY_SOURCE))\n";
boost::python::exec(importModuleStream.str().c_str(), mainNameSpace, locals);
auto pythonScript = locals["newModule"];
auto pythonFunction = pythonScript_.attr(pythonFunctionName .c_str());
pythonFunction(/* args */);
Now the questions are:
Can I interrupt/abort the execution of pythonFunction() after I triggered it? If it is not possible the way I called it, is there another way to call a Python function with Boost Python, so I could abort the call?
I am running under Linux (just in case this enables some platform dependent solution, that I would be totally cool with).
I have not found a true "stop interpreter from the outside" approach. But I created a workaround that at least gets the job done in my situation. Maybe it will help someone else...
The idea is that I have a thread inside the Python script that does nothing else but waits to be woken up. It gets woken up by a call to an "abort" function from within C++. Once it is awake it kills the script from the inside. I chose a crude approach to stop the script in this example:
os._exit(1)
There are sure nicer ways to do this, but this is beyond the point right here. The whole abort and terminate stuff can also be wrapped nicer, but once again: I just want to sketch the idea.
My test Python script looks like this:
import threading
import time
import os
def abort():
global run
run = False
global condition
with condition:
condition.notify()
def threadBlock():
while True:
print( "Blocking!" )
time.sleep(3)
def threadTerminate():
while run:
global condition
with condition:
condition.wait()
global kill
if kill:
os._exit(1)
def myEntryFunction()
blockingThread = threading.Thread( target = threadBlock )
terminatingThread = threading.Thread( target = threadTerminate )
blockingThread.start()
terminatingThread.start()
threadBlock().join()
global kill
kill = False
global condition
with condition:
condition.notify()
terminatingThread.join()
run = True;
kill = True;
condition = threading.Condition()
From within C++ I kill the script like this:
// other code (see question)
std::thread killer([&pythonScript] () {
std::chrono::seconds d(15);
std::this_thread::sleep_for(d);
AcquireGIL gil;
pythonScript.executeFunction("abort");
});
pythonFunction(/* args */);
With AcquireGIL looking like this:
#include <boost/python.hpp>
class AcquireGIL final
{
public:
AcquireGIL();
~AcquireGIL();
private:
PyGILState_STATE gilState_;
};
AcquireGIL::AcquireGIL()
: gilState_(PyGILState_Ensure()) {
// nothing to do...
}
AcquireGIL::~AcquireGIL() {
PyGILState_Release(gilState_);
}
Edit
Different (similar) approach
In the entry function of my script I start a thread as daemon that calls a helper function. The helper function calls a worker method (that does the stuff I actually want to do). After the worker method returns, the helper signals a condition variable. The main thread just waits for this condition. If I want to abort from the outside, I just notify the condition as well. When the main thread ends, the helper thread already ended or in case of an abort from the outside, will be cleaned up.
Attention
In case of an abort the helper thread will not be able to clean up properly. So you have to cope with that or take care of it manually.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.