[英]How to wrap multithreaded C++ library using Python C/API?
這是一個有點長的問題,但我希望我能清楚地表達出來。
我正在嘗試使用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回溯顯示
程序收到信號SIGSEGV,分段故障。
__pthread_mutex_lock(mutex = 0x0)在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如何與pthread配合使用的權威性文檔?
從您的描述來看,這聽起來根本不是一個線程問題:您聲稱自己在不使用Python API的情況下定義了Dummy
類,但這意味着Dummy
實例不是PyObjects ,因此reinterpret_cast會做錯事。 您不能僅通過實例化C ++類來創建PyObject。 您需要與Python的對象系統一起使用,並創建適當的PyType結構和PyObject結構,並正確地初始化兩者。 您還需要確保您的引用計數正確。
排序后,要記住的關於線程的主要事情是,任何接觸Python對象或使用任何Python API的調用(獲取GIL的函數除外)都必須獲取GIL 。 如果C ++庫中的任何線程嘗試回調Python代碼或觸摸Python對象,則需要將訪問包裝在PyGILState_Ensure
/ PyGILState_Release
。
謝謝托馬斯指出紅鯡魚。 問題出在C ++端的線程初始化中。 是的,它不需要任何GIL操作,因為沒有其他C ++線程在訪問Python C / API。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.