2012-03-05 3 views
4

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

Я реализовал механизм обратного вызова для обновлений с использованием SWIG's directors feature, а при тестировании с помощью 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 при вызове функции обратного вызова.
Мое подозрение это:Я нарушил GIL
AFAIU обновления происходят из кода другого потока и вызовите питона, используя эту нить.

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

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

+0

[Этот пост в списке рассылки SWIG] (http: //article.gmane.org/gmane.comp.programming.swig/5306/match=multi+threading+python) говорит именно об этой проблеме и призывает к действиям по ее исправлению в SWIG. Я думаю, что это не было рассмотрено с 2004 года. – Jonathan

ответ

2

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

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

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

+0

Я обнаружил, что если вы используете директоров SWIG, вам нужно будет заблокировать GIL самостоятельно, если другой поток/процесс вызовет обратный вызов. – AndyG

Смежные вопросы