这是一个有点长的问题,但我希望我能清楚地表达出来。
我正在尝试使用Python / C API包装C ++库。主库,比如 mylib ,有自己的对象系统(它类似于另一种语言的解释器),并通过 Id 唯一地标识其环境中的每个对象。它在init()
函数中创建多个线程,并在不同的线程上执行不同的操作(比如在一个线程上创建对象并在另一个线程中解释命令)。
现在我试图把它包装在两个层面:
我使用mylib中对象的 Id 创建了一个 Dummy 类。 Dummy构造函数实际上在mylib中调用一个函数来创建一个新对象并存储其Id。 Dummy类中的其他方法类似地调用mylib中的等效函数。这不使用Python / C API。
我创建了mylibmodule.cpp
,它使用Python / C API提供将从Python解释器调用的函数。
我在init()
中调用了mylib的PyMODINIT_FUNC init_mylib()
函数。
我的代码函数如下:
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回溯显示
编程接收信号SIGSEGV,分段故障。
pthread_mutex_lock.c上的__ pthread_mutex_lock(mutex = 0x0):50
更有趣的是,如果我禁用在mylib代码中生成多个线程(仍与pthreads链接),我可以创建MyClass实例,但是在退出Python解释器时会出现分段违规。
Python文档中的“Thin Ice”部分(http://docs.python.org/extending/)没有启发我。我想知道是否应该在mylibmodule.cpp中的所有Python C / API调用周围使用PyGILState_Ensure和PyGILState_Release。或者应该是Py_BEGIN_ALLOW_THREADS和Py_END_ALLOW_THREADS?
有人可以帮忙吗?是否有关于Python与pthreads完全匹配的确切文档?
答案 0 :(得分:3)
根据您的描述,它听起来根本不是一个线程问题:您声称在不使用Python API的情况下定义Dummy
类,但这意味着Dummy
个实例是不是PyObjects ,所以reinterpret_cast会做错事。您不能通过实例化C ++类来创建PyObjects;你需要与Python的对象系统一起使用并创建一个合适的PyType结构和一个PyObject结构并正确地初始化它们。您还需要确保您的引用是正确的。
一旦你有了这个排序,关于线程要记住的主要事情是任何涉及Python对象的调用或使用任何Python API的任何调用(除了获取GIL的函数除外)都必须获得GIL < / em>的。如果C ++库中的任何线程尝试回调Python代码或触摸Python对象,则需要将访问权限包含在PyGILState_Ensure
/ PyGILState_Release
中。
答案 1 :(得分:0)
谢谢托马斯指出红鲱鱼。问题出在C ++端的线程初始化中。 是的,它不需要任何GIL操作,因为没有其他C ++线程访问Python C / API。