这是一个有点长的问题,但我希望我能表达清楚。
我正在尝试使用 Python/C API 包装一个 C++ 库。主库,比如说,mylib,有自己的对象系统(它有点像另一种语言的解释器),并通过 Id 唯一标识其环境中的每个对象。它在其 init()
函数中创建多个线程,并在不同的线程上执行不同的操作(比如在一个线程上创建对象并在另一个线程中解释命令)。
现在我试图将它分为两个层次:
我用 mylib 中对象的 Id 创建了一个 Dummy 类。 Dummy 构造函数实际上调用了 mylib 中的一个函数来创建一个新对象并存储它的 Id。 Dummy 类中的其他方法类似地调用 mylib 中的等效函数。这不使用 Python/C API。
我创建了
mylibmodule.cpp
,它使用 Python/C API 提供将从 Python 解释器调用的函数。我在
PyMODINIT_FUNC init_mylib()
中调用了mylib的init()
函数。我编写如下函数:
static PyObject * py_new_Dummy(PyObject* self, PyObject *args){ // ... process arguments return reinterpret_cast<PyObject*>(new Dummy); }
请注意,Dummy 构造函数会调用 mylib 中的函数,这些函数是在使用 pthreads 创建的线程上执行的。
我将其编译成 _mylib.so 并且我有一个 mylib.py:
import _mylib
class MyClass(obj):
def __init__(self, *args)
self.__ptr = _mylib.py_new_Dummy()
现在进入实际问题:我可以在 Python 解释器中导入 mylib,但一旦尝试:
a = MyClass(some_args)
我遇到了段错误。 gdb 回溯显示
Program received signal SIGSEGV, Segmentation fault.
__pthread_mutex_lock (mutex=0x0) at pthread_mutex_lock.c:50
更有趣的是,如果我在 mylib 代码中禁用生成多个线程(仍然与 pthreads 链接),我可以创建 MyClass 实例,但我在退出 Python 解释器时遇到分段冲突。
Python 文档 (http://docs.python.org/extending/) 中的“Thin Ice”部分没有启发我。我想知道我是否应该在 mylibmodule.cpp 中围绕所有 Python C/API 调用使用 PyGILState_Ensure 和 PyGILState_Release。或者应该是 Py_BEGIN_ALLOW_THREADS 和 Py_END_ALLOW_THREADS?
有人可以帮忙吗?是否有关于 Python 如何与 pthreads 一起玩的权威文档?
最佳答案
从你的描述来看,这听起来根本不像是线程问题:你声称你定义了 Dummy
类而不使用 Python API,但这意味着 Dummy
实例不是 PyObjects,所以 reinterpret_cast 会做错事。您不能仅通过实例化 C++ 类来创建 PyObjects;您需要使用 Python 的对象系统并创建适当的 PyType 结构和 PyObject 结构并正确初始化两者。您还需要确保您的 refcounts 是正确的。
一旦你完成排序,关于线程要记住的主要事情是任何接触 Python 对象或使用任何 Python API 的调用(除了获取 GIL 的函数)必须获得 GIL。如果您的 C++ 库中的任何线程试图回调 Python 代码或接触 Python 对象,则访问需要包装在 PyGILState_Ensure
/PyGILState_Release
中。
关于c++ - 如何使用 Python C/API 包装多线程 C++ 库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5416368/