Cython 回调导致内存损坏/段错误
我正在使用 cython 将 python 与 c++ 库连接起来。我需要一个 C++ 代码可以调用的回调函数。我还需要将对特定 python 对象的引用传递给此函数。从回调演示中可以清楚地看出这一点。
但是,当从 c++ 线程(pthread)调用回调时,我会遇到各种错误:
- 将函数指针和类/对象(作为 void*)传递给 c++
- 将指针存储在 c++ 中
- 启动运行循环的新线程(pthread)
- 使用存储的函数指针调用函数并传回类指针(void*)
- 在 python 中:将 void* 转换回类/对象
- 调用上述类/对象的方法 (错误)
步骤 2 和 3 在 c++ 中。
这些错误主要是分段错误,但有时我会抱怨一些低级别的 python 调用。
我有完全相同的代码,在 python 中创建一个线程并直接调用回调。这工作正常。所以回调本身正在工作。
我确实需要一个在 C++ 中运行的单独线程,因为该线程正在与硬件通信,并且有时会调用我的回调。
我还对所有正在传递的指针进行了三次检查。它们指向有效的位置。
我怀疑从 C++ 线程使用 cython 类时存在一些问题..?
我在 Ubuntu 上使用 Python 2.6.6。
所以我的问题是: 我可以从非 python 线程操作 python 对象吗? 如果没有,有没有办法让线程兼容Python? (pthread)
这是从 C++ 线程调用时已经导致问题的最小回调:
cdef int CheckCollision(float* Angles, void* user_data):
self = <CollisionDetector>user_data
return self.__sizeof__() # <====== Error
I am interfacing python with a c++ library using cython. I need a callback function that the c++ code can call. I also need to pass a reference to a specific python object to this function. This is all quite clear from the callback demo.
However I get various errors when the callback is called from c++ thread (pthread):
- Pass function pointer and class/object (as void*) to c++
- Store the pointers within c++
- Start new thread (pthread) running a loop
- Call function using the stored function pointer and pass back the class pointer (void*)
- In python: cast void* back to class/object
- Call a method of above class/object (Error)
Steps 2 and 3 are in c++.
The errors are mostly segmentation faults but sometimes I get complaints about some low level python calls.
I have the exact same code where I create a thread in python and call the callback directly. This works OK. So the callback itself is working.
I do need a separate thread running in c++ since this thread is communicating with hardware and on occasion calling my callback.
I have also triple-checked all the pointers that are being passed around. They point to valid locations.
I suspect there are some problems when using cython classes from a c++ thread..?
I am using Python 2.6.6 on Ubuntu.
So my question is:
Can I manipulate python objects from a non-python thread?
If not, is there a way can make the thread python-compatible? (pthread)
This is the minimal callback that already causes problems when called from c++ thread:
cdef int CheckCollision(float* Angles, void* user_data):
self = <CollisionDetector>user_data
return self.__sizeof__() # <====== Error
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不,在没有首先获取 GIL 的情况下,您不能操作 Python 对象。您必须使用
PyGILState_Ensure()
+PyGILState_Release()
(请参阅 PyGILState_Ensure 文档)如果你明确地获取引用,并在以下情况下释放它,你可以确保你的对象不会被 python 删除:您不再将其与
Py_INCREF()
和Py_DECREF()
一起使用。如果你将回调传递给你的c++,并且你不再有引用,也许你的python对象被释放,并且崩溃发生(参见Py_INCREF 文档)。免责声明:我并不是说这是您的问题,只是为您提供追踪错误的提示:)
No, you must not manipulate Python objects without acquiring GIL in the first place. You must use
PyGILState_Ensure()
+PyGILState_Release()
(see the PyGILState_Ensure documentation)You can ensure that your object will be not deleted by python if you explicitly take the reference, and release it when you're not using it anymore with
Py_INCREF()
andPy_DECREF()
. If you pass the callback to your c++, and if you don't have a reference taken anymore, maybe your python object is freed, and the crash happen (see the Py_INCREF documentatation).Disclamer: i'm not saying this is your issue, just giving you tips to track down the bug :)