SWIG C ++ Python полиморфизм и многопоточность - PullRequest
5 голосов
/ 05 марта 2012

Я интегрирую сторонний пакет C ++ в приложение Python, используя SWIG .Пакет подключается к проприетарному API через сеть и получает обновления.Весь процесс заключается в том, что python создает экземпляр объекта C ++, вызывает его функции, чтобы установить его, и затем ждет обновлений.

Я реализовал механизм обратного вызова для обновлений, используя функция директоров SWIG ,и при тестировании из python или из функций C ++, вызываемых python, это работает хорошо.А именно, я могу наследовать класс C ++ в Python, вызывать его виртуальные функции из C ++ и видеть, что код python имеет приоритет и выполняется.

Проблема:
Когда я получаюобновления из сети, которые я получаю:

The thread 'Win32 Thread' (0x1f78) has exited with code 0 (0x0).
Unhandled exception at 0x1e0650cb in python.exe: 0xC0000005: Access violation writing location 0x0000000c.

Это исключение выдается изнутри python27.dll при вызове функции обратного вызова.
Мое подозрение таково: IВы нарушили GIL
AFAIU. Обновления приходят из другого потока и вызывают код Python, используя этот поток.

На данный момент я в растерянности.Функция директора SWIG ограничена только потоками, инициированными в python (т.е. из потоков, управляемых python)?
Как мне обойти это?Как заставить обновления с C ++ на python?Можно ли вообще использовать SWIG?
Должен ли я использовать совершенно другой подход?

Я открыт для любых предложений по этому вопросу ...

1 Ответ

4 голосов
/ 30 июня 2012

Если ваш код C ++ в оболочке SWIG вызывает подпрограмму обратного вызова в потоке, то, вероятно, проблем с GIL нет - код, сгенерированный SWIG, не выполняет никакого управления GIL, которое я видел, что означает, что при вызове кода Pythonв вашем коде C ++ вы сохраняете GIL на протяжении всего вызова.

Однако, если ваш код C ++ откладывает обратный вызов в другой поток, то вы, скорее всего, нарушили GIL.Это достаточно просто для обхода: перед вызовом обратного вызова вызовите PyGILState_Ensure (), а после завершения обратного вызова вызовите PyGILState_Release.См. http://docs.python.org/c-api/init.html, раздел «Потоки, не созданные Python».(Если вы используете здесь обработку исключений в C ++, вам может потребоваться проявить особую осторожность, чтобы гарантировать возможность выпуска GIL.)

Если вы еще не просматривали трассировку стека, стоит проверить, чтоэтот пустой указатель не является чем-то глупым в вашем коде.(Вы можете подключиться к процессу Python, выполняющему ваш код, с помощью VS / GDB / WinDBG; выполнение Python останется непостижимым, но вы можете отслеживать свой код C ++ таким образом.)

...