Есть ли способ заставить boost :: python контролировать Python GIL для каждого взаимодействия с python?
Я пишу проект с boost :: python. Я пытаюсь написать оболочку C ++ для внешней библиотеки и управлять библиотекой C ++ с помощью сценариев Python. Я не могу изменить внешнюю библиотеку, только мою программу-обертку. (Я пишу приложение функционального тестирования для указанной внешней библиотеки)
Внешняя библиотека написана на C и использует указатели функций и обратные вызовы для выполнения большой работы. Это система обмена сообщениями, поэтому, когда приходит сообщение, вызывается функция обратного вызова, например.
Я реализовал шаблон наблюдателя в своей библиотеке, чтобы несколько объектов могли прослушивать один обратный вызов. У меня все основные игроки экспортированы должным образом, и я могу контролировать вещи до определенного момента.
Внешняя библиотека создает потоки для обработки сообщений, отправки сообщений, обработки и т. Д. Некоторые из этих обратных вызовов могут вызываться из разных процессов, и недавно я обнаружил, что python не является потокобезопасным.
Эти наблюдатели могут быть определены в Python, поэтому я должен иметь возможность вызывать Python, а Python должен вызывать мою программу в любой момент.
Я настраиваю объект и наблюдателя примерно так
class TestObserver( MyLib.ConnectionObserver ):
def receivedMsg( self, msg ):
print("Received a message!")
ob = TestObserver()
cnx = MyLib.Conection()
cnx.attachObserver( ob )
Затем я создаю источник для отправки в соединение и вызывается функция receiveMsg.
Итак, обычный source.send ('msg') войдет в мое приложение C ++, перейдет в библиотеку C, которая отправит сообщение, получит соединение, затем вызовет функцию обратного вызова, которая возвращается в мой C ++ библиотека и соединение пытается уведомить всех наблюдателей, которые на данный момент являются классом python, поэтому он вызывает этот метод.
И, конечно, обратный вызов вызывается из потока соединения, а не из основного потока приложения.
Вчера все рушилось, я не смог отправить 1 сообщение. Затем, покопавшись в архивах Cplusplus-sig, я узнал о GIL и нескольких изящных функциях для блокировки вещей.
Так что моя оболочка C ++ для моего класса-наблюдателя теперь выглядит так
struct IConnectionObserver_wrapper : Observers::IConnectionObserver, wrapper<Observers::IConnectionObserver>
{
void receivedMsg( const Message* msg )
{
PyGILState_STATE gstate = PyGILState_Ensure();
if( override receivedMsg_func = this->get_override( "receivedMsg" ) )
receivedMsg_func( msg );
Observers::IConnectionObserver::receivedMsg( msg );
PyGILState_Release( gstate );
}
}
И это РАБОТАЕТ, однако, когда я пытаюсь отправить более 250 сообщений примерно так
for i in range(250)
source.send('msg")
снова падает. С тем же сообщением и симптомами, что и раньше,
PyThreadState_Get: no current thread
поэтому я думаю, что в этот раз у меня возникла проблема с вызовом моего приложения на C ++, а не с вызовом на python.
У меня вопрос, есть ли способ заставить boost :: python обрабатывать сам GIL для каждого взаимодействия с python? Я не могу найти ничего в коде, и это действительно трудно, пытаясь найти, где вызов source.send входит в boost_python: (