boost :: pythonがpythonとのすべての相互作用のためにPythonGILを制御するようにする方法はありますか?
私はboost::pythonでプロジェクトを書いています。外部ライブラリのC++ラッパーを作成し、PythonスクリプトでC++ライブラリを制御しようとしています。外部ライブラリを変更できません。ラッパープログラムのみを変更できます。(私は上記の外部ライブラリの機能テストアプリケーションを書いています)
外部ライブラリはCで記述されており、関数ポインタとコールバックを使用して多くの手間のかかる作業を行います。そのメッセージングシステムであるため、メッセージが着信すると、たとえばコールバック関数が呼び出されます。
複数のオブジェクトが1つのコールバックをリッスンできるように、ライブラリにオブザーバーパターンを実装しました。私はすべての主要なプレーヤーを適切にエクスポートしており、特定の時点まで非常にうまく制御できます。
外部ライブラリは、メッセージの処理、メッセージの送信、処理などを行うスレッドを作成します。これらのコールバックの一部は異なるプロセスから呼び出される可能性があり、最近、Pythonはスレッドセーフではないことがわかりました。
これらのオブザーバーはPythonで定義できるため、Pythonを呼び出すことができる必要があり、Pythonはいつでもプログラムを呼び出す必要があります。
オブジェクトとオブザーバーをそのように設定します
class TestObserver( MyLib.ConnectionObserver ):
def receivedMsg( self, msg ):
print("Received a message!")
ob = TestObserver()
cnx = MyLib.Conection()
cnx.attachObserver( ob )
次に、接続に送信するソースを作成し、receivedMsg関数を呼び出します。
したがって、通常のsource.send('msg')はC ++アプリに移動し、Cライブラリに移動してメッセージを送信します。接続はメッセージを取得し、コールバックを呼び出します。コールバックはC++ライブラリに戻ります。 connectionは、すべてのオブザーバーに通知しようとします。この時点では、ここではpythonクラスであるため、そのメソッドを呼び出します。
そしてもちろん、コールバックはメインのアプリケーションスレッドではなく、接続スレッドから呼び出されます。
昨日はすべてがクラッシュしていて、1つのメッセージを送信できませんでした。次に、Cplusplus-sigアーカイブを調べた後、GILと、物事をロックするためのいくつかの気の利いた機能について学びました。
したがって、オブザーバークラスのC++pythonラッパーは次のようになります
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
そのため、今回はPythonを呼び出すのではなく、C++アプリを呼び出すときに問題が発生すると考えています。
私の質問は、boost :: pythonがpythonとのすべての相互作用のためにGIL自体を処理するようにする方法はありますか?コード内に何も見つかりません。source.send呼び出しがboost_pythonに入る場所を見つけるのは非常に困難です:(