Как обернуть многопоточную библиотеку C ++ с помощью Python C / API? - PullRequest
0 голосов
/ 24 марта 2011

Это довольно длинный вопрос, но я надеюсь, что смогу его четко выразить.

Я пытаюсь обернуть библиотеку C ++, используя Python / C API. Основная библиотека, скажем, mylib , имеет свою собственную объектную систему (это что-то вроде интерпретатора для другого языка) и однозначно идентифицирует каждый объект в своей среде по Id . Он создает несколько потоков в своей функции init() и выполняет разные операции в разных потоках (например, создает объекты в одном потоке и интерпретирует команды в другом потоке). Сейчас я пытаюсь обернуть его в два уровня:

  1. Я создал Dummy класс с Id объекта в mylib. Конструктор Dummy на самом деле вызывает функцию в mylib для создания нового объекта и сохранения его идентификатора. Другие методы в классе Dummy аналогичным образом вызывают эквивалентные функции в mylib. Это не использует Python / C API.

  2. Я создал mylibmodule.cpp, который использует API Python / C для предоставления функций, которые будут вызываться из интерпретатора 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()

Теперь к актуальной проблеме: я могу импортировать mylib в интерпретатор Python, но как только я попытаюсь:

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/) не просветил меня. Мне интересно, стоит ли мне использовать PyGILState_Ensure и PyGILState_Release для всех вызовов Python C / API в mylibmodule.cpp. Или это должен быть Py_BEGIN_ALLOW_THREADS и Py_END_ALLOW_THREADS

Кто-нибудь может помочь? Есть ли какая-либо определенная документация о том, как именно Python играет с pthreads?

Ответы [ 2 ]

3 голосов
/ 24 марта 2011

Из вашего описания это совсем не похоже на проблему многопоточности: вы утверждаете, что определяете класс Dummy без использования Python API, но это будет означать, что Dummy экземпляры не являются PyObjects , так что reinterpret_cast сделает не то, что нужно. Вы не можете создавать PyObjects, просто создав экземпляр класса C ++; вам нужно поиграть с объектной системой Python, создать правильную структуру PyType и структуру PyObject и правильно инициализировать обе. Вы также должны убедиться, что ваши счета правильные.

После того как вы отсортировали, главное, что нужно помнить о потоках, это то, что любой вызов, который касается объектов Python или использует какой-либо из API-интерфейсов Python (кроме функций для захвата GIL) должен иметь полученный GIL . Если какой-либо из потоков в вашей библиотеке C ++ пытается перезвонить коду Python или коснуться объектов Python, доступ должен быть заключен в PyGILState_Ensure / PyGILState_Release.

0 голосов
/ 24 марта 2011

Спасибо, Томас, за указание на красную сельдь.Проблема была в инициализации потоков на стороне C ++.И да, он не нуждался в каких-либо манипуляциях с GIL, поскольку ни один из дополнительных потоков C ++ не обращался к Python C / API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...