0

boost::python とコールバック駆動の実行を含むプロジェクトで問題が発生しています。

私のプロジェクトでは、C++ から Python コードを実行するためにコールバック メカニズムを使用しています。

コールバックの実行を引き起こす最初の関数呼び出しが Python インタープリターからのものである限り、すべて問題ありません。例えば:

h = CallbackHandler()

def mycallback():
    print "yeah"

h.setCallback(mycallback)

h.runCallback()

# will print yeah

残念ながら、それはそれほど単純ではありません。私のプロジェクトはRtAudioを使用してオーディオ環境と通信します。RtAudio の実行はコールバック駆動型です。RtAudio にコールバック関数を渡します。RtAudio を開始すると、サウンドの計算が必要になるたびにコールバックが呼び出されます。

RtAudio のコールバック駆動型実行を使用すると、コードが C++ から Python コールバックを実行しようとするとすぐにセグメンテーション違反が発生します。

コールバック駆動型の実行を開始するには、ノンブロッキングの関数 start() を呼び出す必要があります。これは、コールバック駆動の実行が別のスレッドで発生することを意味します。

次に、python から start() を呼び出すときに、python の実行環境に個別にアクセスする別のスレッドを作成しています。python の GIL を少ししか理解していないため、これは良くありません。

では、このコールバック駆動型スレッドで、すべてを分割せずに Python コールバックを実行するにはどうすればよいでしょうか?

申し訳ありませんが、私の問題の短い、完全に機能する例にコードを単純化する方法を見つけることができませんでした.問題はそこにあります.

編集

Python のドキュメントを調べた後、 Python以外で作成されたスレッドが Python 環境にアクセスしようとしたときに、スレッド セーフを処理するコードを数行追加しました。

gstate = PyGILState_Ensure();
while (!queue.empty() && queue.top()->next <= now ) {
    queue.top()->run();
    queue.pop();
}
PyGILState_Release(gstate);

しかし、私はまだセグメンテーション違反を起こします。だから私はvalgrindを通してそれを実行しました、そしてここに私が得たものがあります(valgrindが常にpythonインタープリターから取得する奇妙なものを差し引いたもので、これは「通常」です):

==31836== Thread 2:
==31836== Invalid read of size 4
==31836==    at 0x41F0DD5: sem_post@@GLIBC_2.1 (in /lib/libpthread-2.14.1.so)
==31836==    by 0x5ED294C: callback(void*, void*, unsigned int, double, unsigned int, void*) (in /home/tom/Code/pyck/pyck/libcore.so)
==31836==    by 0x5F6B16B: RtApiAlsa::callbackEvent() (in /usr/lib/librtaudio.so)
==31836==    by 0x5F6BBCC: alsaCallbackHandler (in /usr/lib/librtaudio.so)
==31836==    by 0x42D286D: clone (in /lib/libc-2.14.1.so)
==31836==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==31836== 
==31836== 
==31836== Process terminating with default action of signal 11 (SIGSEGV)
==31836==  Access not within mapped region at address 0x0
==31836==    at 0x41F0DD5: sem_post@@GLIBC_2.1 (in /lib/libpthread-2.14.1.so)
==31836==    by 0x5ED294C: callback(void*, void*, unsigned int, double, unsigned int, void*) (in /home/tom/Code/pyck/pyck/libcore.so)
==31836==    by 0x5F6B16B: RtApiAlsa::callbackEvent() (in /usr/lib/librtaudio.so)
==31836==    by 0x5F6BBCC: alsaCallbackHandler (in /usr/lib/librtaudio.so)
==31836==    by 0x42D286D: clone (in /lib/libc-2.14.1.so)
==31836==  If you believe this happened as a result of a stack
==31836==  overflow in your program's main thread (unlikely but
==31836==  possible), you can try to increase the size of the
==31836==  main thread stack using the --main-stacksize= flag.
==31836==  The main thread stack size used in this run was 8388608.
==31836== 
==31836== HEAP SUMMARY:
==31836==     in use at exit: 2,313,541 bytes in 2,430 blocks
==31836==   total heap usage: 22,140 allocs, 19,710 frees, 22,007,627 bytes allocated
==31836== 
==31836== LEAK SUMMARY:
==31836==    definitely lost: 522 bytes in 5 blocks
==31836==    indirectly lost: 0 bytes in 0 blocks
==31836==      possibly lost: 66,669 bytes in 1,347 blocks
==31836==    still reachable: 2,246,350 bytes in 1,078 blocks
==31836==         suppressed: 0 bytes in 0 blocks
==31836== Rerun with --leak-check=full to see details of leaked memory
==31836== 
==31836== For counts of detected and suppressed errors, rerun with: -v
==31836== Use --track-origins=yes to see where uninitialised values come from
==31836== ERROR SUMMARY: 2703 errors from 196 contexts (suppressed: 83 from 13)

うまくいけば、コールバック関数は NULL ポインタにアクセスしようとしていますか?

編集2

わかりました、私はこれらすべてを発見しています。pthread のドキュメントから、セマフォsem_post(sem)sem指す への呼び出しがあるようです。しかし、そこでは NULL を指しています。

さて、どうすればエラーをより正確に特定できますか?

4

1 に答える 1

0

あなたはGILに反抗していると思います。私の推測では、コールバックコードはPythonインタープリターに飛び込む前にGILを取得していません。

また、GILを使用するすべてのスレッドは、登録する前に自分自身を登録する必要がある場合があります。また、コールバックを実行しているスレッドはそれ自体を登録していません。

C++コールバックがPythonコールバックを実行しないように設定します。代わりに、Pythonプログラムが読み取っているソケットに関連データを書き込みます。次に、Pythonプログラムは、ソケットから関連データを取得するときにコールバックを実行できます。

于 2011-12-17T20:45:25.173 に答える