使用boost.python时进程异常失败
我使用boost.python来调用脚本。每个Python脚本都有三个功能:
- 初始化 - 这个功能必须在开始时调用
- 反初始化 - 这个功能必须在结束时调用,用来关闭所有对象。
- 处理 - 这个功能必须在初始化和反初始化之间多次调用。
这个类不需要解释:
class PyInit
{
public:
PyInit() { Py_Initialize(); }
~PyInit() { Py_Finalize(); }
};
这个类创建了一个PyInit对象实例,然后初始化所有Python对象,并在构造函数中调用"Initialize()"这个Python函数。并在析构函数中调用"Uninitialize()"。
这个类还有一个"Process"函数,可以在类外部多次调用。
class PyGuard
{
public:
explicit PyGuard(const char* pypath)
{
try
{
_main_module = boost::python::import("__main__");
_main_namespace = _main_module.attr("__dict__");
boost::python::object ignored = exec_file(pypath, _main_namespace);
_Initialize = _main_namespace["Initialize"];
_Process = _main_namespace["Process"];
_Uninitialize = _main_namespace["Uninitialize"];
_InitRes = _Initialize();
_ProcRes = boost::python::object();
}
catch(boost::python::error_already_set&)
{
string res;
py_utils::err_parse(res);
throw string("Python exception: " + res);
}
catch(std::exception& e)
{
throw string("C++ exception: " + string(e.what()));
}
catch(...)
{
throw string("Unhandled exception!");
}
}
virtual ~PyGuard()
{
_Uninitialize(_InitRes, _ProcRes);
}
void Process()
{
_ProcRes = _Process(_InitRes, _ProcRes);
}
private:
py_utils::PyInit _initPython;
boost::python::object _InitRes;
boost::python::object _ProcRes;
boost::python::object _Process;
boost::python::object _Initialize;
boost::python::object _Uninitialize;
boost::python::object _main_module;
boost::python::object _main_namespace;
};
只有"Process"函数会出现"boost::python::error_already_set"的异常,这时当前的PyGuard实例会被删除,然后重新创建一个新的。这样做是为了避免可能隐藏的依赖关系,这些依赖关系可能是隐藏异常的结果。
所以,在出现异常后,所有的Python相关内容都会被移除(甚至会调用Py_Finalize()),然后再重新创建。
不过,经过4到10次这样的异常后,整个C++进程会崩溃。
崩溃时,连捕获异常的代码都无法处理:
try
{
_PyGuard = make_shared<PyGuard>("my script");
while(true)
{
try {
_PyGuard->Process();
}
catch()
{
bool inited = false;
while(!inited)
{
try
{
_pyGuard = nullptr;
_pyGuard = make_shared<PyGuard>("script path.txt");
inited = true;
}
catch(string& e)
{
}
}
}
}
_PyGuard = nullptr;
}
catch(...)
{
//falling, it never being catched here.
}
所以,我的问题是,为什么会崩溃并且无法捕获?
我发现崩溃发生在这一行:
_pyGuard = make_shared<PyGuard>("script path.txt");
调用时,所以我觉得这是Python抛出的异常,无法被捕获。为什么会这样?如何防止它?
1 个回答
1
你可能在使用 Py_Finalize()
时遇到了问题。根据 Boost 1.55 的文档,你不应该在使用 Boost.Python 时调用 Py_Finalize()
。看起来你的程序其实并不需要这个结束操作,所以你可以试着把 ~PyInit()
中的这个调用去掉。
如果你真的有某种原因需要进行结束操作,可以看看 Py_NewInterpreter()
。
至于你提到的“无法捕获的异常”问题,这通常是因为同时有两个活动的异常。当这种情况发生时,C++ 会直接中止程序。这可能就是你代码中发生的情况(也可能不是)。