【问题标题】:How to prevent Python from throwing back to C++ boost::python::error_already_set?如何防止 Python 退回到 C++ boost::python::error_already_set?
【发布时间】:2017-05-08 02:44:27
【问题描述】:

我需要在问题之前给出一些背景信息。请多多包涵。使用 boost::python 我向 Python 公开了一些异常类型,比如MyExceptionType。我有一个boomTest,我将它暴露给 Python 以检查它是否有效。 Python 调用boomTest 并正确处理MyExceptionType,到目前为止一切顺利。这是 C++ 的一面:

static void boomTest() {
    throw MyExceptionType("Smoked too many Cohibas!");
}

static PyObject *myExceptionPtr = NULL;
static void translate(MyExceptionType const &exception) {
    assert(myExceptionPtr != NULL);
    boost::python::object pythonExceptionInstance(exception);
    PyErr_SetObject(myExceptionPtr, pythonExceptionInstance.ptr());
}

BOOST_PYTHON_MODULE(test) {
    class_<MyExceptionType> myException("MyExceptionType", no_init);
    myException.add_property("message", &MyExceptionType::what);
    myExceptionPtr = myException.ptr();
    register_exception_translator<MyExceptionType>(&translate);
}

这就是 Python 的一面:

import sys

import example
reload(example)
from example import MyExceptionType, boomTest

def tryBoomTest():
    try:
        boomTest()

    except MyExceptionType as ex:
        print 'Success! MyExceptionType gracefully handled:' \
            '\n message="%s"' % ex.message
    except:
        print 'Caught unhandled exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])

现在事情变得有点棘手,因为在一个真实的用例中,我有一个从 C++ Boost(非 Python)线程到 Python 的回调,如下所示:

# this is a Python callback invoked from a C++ boost non-Python thread
def handle(future):
    try:
        # future.get() throws MyExceptionType if there was a cluster exception
        "Cluster response received with value: %s" % future.get()

    except MyExceptionType as ex:
        print 'Success! MyExceptionType gracefully handled:' \
            '\n message="%s"' % ex.message

现在是 OP

future.get() 调用抛出一个供Python 处理的MyExceptionType 时,为什么我的C++ 回调触发器会得到一个boost::python::error_already_set 异常?我怀疑这种行为是由于异常是在 C++(非 Python)线程中引发的......

需要什么来强制 Python 像开头的示例那样处理异常?

我已经尝试在 C++ 的回调触发器中执行以下操作:

void callbackTrigger() {
    try {
        pythonHandle_(getFuture());
    }
    // why do I get this???
    catch (boost::python::error_already_set&) {
        // this doesn't help, Python doesn't still handle MyExceptionType
        boost::python::handle_exception();
    }
}

【问题讨论】:

    标签: python c++ exception-handling boost-python


    【解决方案1】:

    我验证了我的理论,即 Python 不喜欢处理抛出的异常(即使在 Python 代码中),而是作为外来 C++ 线程的一部分执行。因此,我构建了这个纯 Python 包装器,以便能够处理 Python 主线程中的回调。

    import example
    reload(example)
    from example import MyExceptionType
    
    condition = threading.Condition()
    futures = []
    
    # Actual handle executed by the main Python THREAD
    # __after__ submitting all the jobs to the Cluster
    # N is the number of jobs that were submitted to the Cluster
    def handle(N):
        while (N > 0):
            condition.acquire()
            try:
                # wait for max of a second to prevent this thread waiting indefinitely
                # when it misses notify while being busy processing responses
                condition.wait(1.0)
                for future in futures:
                    try:
                        print 'callback received! the response is:\n %s' % future.get()
    
                    except MyExceptionType as ex:
                        print 'MyExceptionType gracefully handled:' \
                              '\n message="%s"' % ex.message
                    except:
                        print 'Caught unhandled exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])
            finally:
                N -= len(futures)
                del(futures[:])
                condition.release()
    
    # callback called from a C++ boost THREAD
    def callback(future):
        condition.acquire()
        try:
            # do not consume the future here, rather let the main 
            # Python thread deal with it ...
            futures.append(future)
            condition.notify()
        finally:
            condition.release()
    

    这并不理想,但它可以工作并且输出正确:

    registering callback 1 ...
    registering callback 2 ...
    registering callback 3 ...
    registering callback 4 ...
    registering callback 5 ...
    MyExceptionType gracefully handled:
     message="Smoked too many Cohibas!"
    MyExceptionType gracefully handled:
     message="Smoked too many Cohibas!"
    MyExceptionType gracefully handled:
     message="Smoked too many Cohibas!"
    MyExceptionType gracefully handled:
     message="Smoked too many Cohibas!"
    MyExceptionType gracefully handled:
     message="Smoked too many Cohibas!"
    
    Process finished with exit code 0
    

    【讨论】:

      猜你喜欢
      • 2019-11-17
      • 1970-01-01
      • 1970-01-01
      • 2022-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-05
      • 2023-04-06
      相关资源
      最近更新 更多