2016-11-08 16 views
1

私は、マルチスレッドの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を作成しようとしているのか、それとも連続呼び出しを行うのかを判断する方法はありますか?または、おそらくこのスレッドの問題を回避する方法?

答えて

0

明らかに私は_PyThreadState_Currentを使用することができますが、私はまだこれがなぜ機能するのか100%確信していません。それは!currentThreadの代わりにcurrentThreadであるようです。

void callback(){ 
    PyThreadState * currentThread = _PyThreadState_Current; 
    if (PyGILState_GetThisThreadState() || !currentThread){ 
     PyGILState_STATE gstate; 
     gstate = PyGILState_Ensure(); 
     PyRun_SimpleString(....); 
     PyGILState_Release(gstate); 
    }else{ 
     PyRun_SimpleString(....); 
    } 

正しい方向に私を向けるためにthis postに感謝します。

関連する問題