从本机线程引发 python 异常

问题描述 投票:0回答:1

我有一个 C++ 类

Runner
,它封装了运行本机线程。该类通过
pybind11
暴露给 Python,因此从 Python 中调用
start_thread

class Runner {
public:
    void start_thread() {
        thread_ = std::jthread([]{
            try {
                while (true) {
                    // do something
                }
            } catch (...) {
                pybind11::gil_scoped_acquire gil;
                pybind11::set_error(PyExc_RuntimeError, "Something horrible happend");
            }
        });
    }

private:
    std::jthread thread_;
};

本机线程中可能会抛出异常,有没有办法将异常从本机线程重新引发到Python?

我正在考虑使用 pybind11::set_error,但这是正确的方法吗?如果是这样,当 Python 意识到存在异常时,有什么保证呢?如果本机线程释放 Gil 后立即检查异常 - 那么这个解决方案应该没问题。

python c++ exception pybind11
1个回答
0
投票

就像你注意到的,你不能让 C++ 异常逃逸

jthread
,因为它将在 C++ 端处理并导致崩溃。相对好的方法是将
std::exception_ptr
存储在
Runner
中,并提供额外的接口以将其重新抛出到调用方:

class Runner {
public:
  void start_thread() {
    thread_ = std::jthread([this] {
      try {
        throwSomething();
      } catch (const std::exception &e) {
        ePtr_ = std::current_exception();
      }
    });
  }
  void rethrow_if_needed() const {
    if (ePtr_) {
      std::rethrow_exception(ePtr_);
    }
  }

private:
  void throwSomething() { throw std::runtime_error("crit failure"); }
  std::jthread thread_;
  std::exception_ptr ePtr_;
};

那么你的 python 代码可能如下所示:

runner = Runner()
runner.start_thread()

try:
    time.sleep(1)
    runner.rethrow_if_needed()
except Exception as e:
    print("caught: ", e)

std::runtime_error
应自动翻译为 pythonic
RuntimeError

© www.soinside.com 2019 - 2024. All rights reserved.