【问题标题】:Strange process fail with boost.python奇怪的过程因 boost.python 而失败
【发布时间】:2014-07-16 09:05:36
【问题描述】:

我使用 boost.python 来调用脚本。每个python脚本都有3个功能:

  • 初始化 - 必须在开始时调用
  • 取消初始化 - 必须在结束时调用以关闭每个对象。
  • 进程 - 必须在 Initialize 和 Uninitialize 之间多次调用。

这个类不需要解释:

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;
};

由于只有“进程”因“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 raise 异常不能被捕获。为什么?以及如何预防?

【问题讨论】:

    标签: python c++ exception boost


    【解决方案1】:

    您对Py_Finalize() 的使用可能是问题所在。根据 Boost 1.55 文档,您 shouldn't use Py_Finalize() with Boost.Python。看起来您的程序并不需要最终确定,因此您可以尝试从 ~PyInit() 中删除调用。

    如果您出于某种原因确实需要最终确定,您可以查看Py_NewInterpreter()

    至于您的“无法捕获的异常”问题,这通常是同时具有两个活动异常的结果。发生这种情况时,C++ 将简单地中止。这可能(或可能不会)是您的代码正在发生的事情。

    【讨论】:

    • 谢谢,我去试试!
    • 如果在解析第一个异常之前引发第二个异常,我是否认为一次可以有两个异常?
    • 不,从 catch 块内部抛出异常是完全可以的。在这种情况下,第一个异常被视为“已处理”。您遇到问题的地方是传播一个异常并且 - 在 catch 块之外 - 抛出一个新异常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多