私は、マルチスレッドのCフレームワークに属するC関数をPythonモジュールにラッピングしています。このフレームワークには、特定のイベントがトリガされたときに実行されるコールバックがあります。ただし、コールバックは常に同じスレッドから実行されるわけではありません。異なるスレッドとGIL上のPythonコールバック
私の問題に関連するコールバックは、python ctypesで定義されています。通常のctypesコールバックの問題は、Python C-APIを使用してGILを取得しようとすることです。この取得は、Py_initialize()
を呼び出さなかったスレッドから実行されたときに失敗します。
フレームワークのために、私はコールバックの実行方法を変更できません。私ができる唯一のことは、コールバック関数自体を変更することです。
void* callback(void*){
if (PyGILState_GetThisThreadState()) {
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
PyRun_SimpleString(...);
PyGILState_Release(gstate);
} else {
PyRun_SimpleString(...);
}
}
PyGILState_GetThisThreadState()
機能が非NULL値を返す場合は、コールバックが実行されることを意味:GILは私はPythonのコールバック関数をラップCコールバック関数を行った取得する方法の制御を有効にする
Py_initialize()
と同じスレッドから呼び出されました。つまり、PyGILState APIを使用できます。これは正しく動作します。
else
部分は、コールバックが他のスレッドから実行されたときに実行されます。それはそのスレッドのスタックにのみPythonの呼び出しがある場合は、適切に実行されますが、それはセグメンテーションフォールトが発生しますスタック内の未完成のpythonのコールがある場合:
#0 0x0000003c46ce6cdb in PyImport_GetModuleDict() from /usr/lib64/libpython2.6.so.1.0
#1 0x0000003c46ce6d2b in PyImport_AddModule() from /usr/lib64/libpython2.6.so.1.0`
#2 0x0000003c46cf2fe8 in PyRun_SimpleStringFlags() from /usr/lib64/libpython2.6.so.1.0
...
<framework calls>
...
#19 0x0000003c46cf1daa in PyRun_StringFlags() from /usr/lib64/libpython2.6.so.1.0
#20 0x0000003c46cf3010 in PyRun_SimpleStringFlags() from /usr/lib64/libpython2.6.so.1.0
#21 0x00007fc72c78dbb6 in execString() from ...
は、私が使用して試してみました同様に、他の部分のPyGILStateのAPIが、それは逆の状況になり:コールバックは、デッドロックに連続したPythonの呼び出しが、結果のために成功したことは、スタック内の最初のPythonの呼び出しのとき:私が出た場合
#0 0x0000003c8de0da00 in sem_wait() from /lib64/libpthread.so.0
#1 0x0000003c46cfd428 in PyThread_acquire_lock() from /usr/lib64/libpython2.6.so.1.0
#2 0x0000003c46cd7784 in PyEval_RestoreThread() from /usr/lib64/libpython2.6.so.1.0
#3 0x0000003c46cf0f58 in PyGILState_Ensure() from /usr/lib64/libpython2.6.so.1.0
if(PyGILState_GetThisThreadState()){..}
と同様のGIL状態、PyGILState_Ensure
およびPyGILState_Release
とすると、it以前のPython呼び出しがスタックにある間は正しく動作しますが、スタックにPython呼び出しがない場合は正しく動作しません。
コールバックが最初のPythonを作成しようとしているのか、それとも連続呼び出しを行うのかを判断する方法はありますか?または、おそらくこのスレッドの問題を回避する方法?