2011-02-01 23 views
11

更新 PyGILState_Ensure()の呼び出しがトリックを行う前に、PyEval_InitThreads()を追加するようです。物事を理解するために急いで、私は間違ってPyEval_InitThreads()に私の "ぶら下がり"を帰した。Python PyGILState_ {保証/解放}は、PythonコードからC++に戻るときにsegfaultを引き起こします。

しかし、いくつかのPythonドキュメントを読んだ後、これが正しい解決策であるかどうか疑問に思っています。

グローバルインタープリタロックを持つスレッド(存在する場合)が不明な場合は、この関数を呼び出すのは安全ではありません。特に修正gr_bin_statistics_fブロック - すべての


まず、私はいくつかの修正GNUラジオコードに取り組んでいます。今、私の正確な状況をかなり記述しているバグレポート(古いものだが)がある。バグレポートに記載されている

http://gnuradio.org/redmine/issues/show/199

、usrp_spectrum_sense.pyは、USRP(ラジオ)を再調整するために定期的にバックのPythonへの呼び出し(C++)gr_bin_statistics_fを呼び出します。ここで

は、Pythonのコードが呼び出されたときに何が起こるかです:

PyGILState_STATE d_gstate; 
d_gstate = PyGILState_Ensure(); 

// call python code 

PyGILState_Release(d_gstate); 

だから、私たちはPythonコードから復帰後PyGILState_Release(d_gstate)が呼び出されたときにセグメンテーションフォールトが発生しました。私のコードと元のgr_bin_statistics_fとの間には違いがありますが、これとは遠隔に関連するものはありません。

PyGILState_Ensure()が問題を解決する前にPyEval_InitThreads()を呼び出すと読んでいますが、プログラムがハングするだけです。

誰も私のためにこれに光を当てることはできますか?それとも、GNUラジオのメーリングリストにメッセージを送る時間ですか?

Fedora 14.7でのPython2.7の使用x86_64。探しているため


(gdb) c 
Continuing. 
[New Thread 0x7fabd3a8d700 (LWP 23969)] 
[New Thread 0x7fabd328c700 (LWP 23970)] 
[New Thread 0x7fabd2a8b700 (LWP 23971)] 
[New Thread 0x7fabd228a700 (LWP 23972)] 
[New Thread 0x7fabd1a89700 (LWP 23973)] 
[New Thread 0x7fabd1288700 (LWP 23974)] 
[New Thread 0x7fabd0a87700 (LWP 23975)] 
[New Thread 0x7fabbbfff700 (LWP 23976)] 

Program received signal SIGSEGV, Segmentation fault. 
[Switching to Thread 0x7fabbbfff700 (LWP 23976)] 
0x00000036b3e0db00 in sem_post() from /lib64/libpthread.so.0 
(gdb) bt 
#0 0x00000036b3e0db00 in sem_post() from /lib64/libpthread.so.0 
#1 0x00000036c1317679 in PyThread_release_lock() from /usr/lib64/libpython2.7.so.1.0 
#2 0x00007fabd6159c1f in ~ensure_py_gil_state (this=0x2dc6fc0, x=887000000) 
    at gnuradio_swig_py_general.cc:5593 
#3 gr_py_feval_dd::calleval (this=0x2dc6fc0, x=887000000) at gnuradio_swig_py_general.cc:5605 
#4 0x00007fabd77c4b6e in gr_noise_level_f::tune_window (this=0x2db3ca0, 
    target_freq=) at gr_noise_level_f.cc:97 
#5 0x00007fabd77c554b in gr_noise_level_f::work (this=0x2db3ca0, noutput_items=7, 
    input_items=, output_items=) 
    at gr_noise_level_f.cc:115 
#6 0x00007fabd7860714 in gr_sync_block::general_work (this=0x2db3ca0, 
    noutput_items=, ninput_items=, 
    input_items=, output_items=) at gr_sync_block.cc:64 
#7 0x00007fabd7846ce4 in gr_block_executor::run_one_iteration (this=0x7fabbbffed90) 
    at gr_block_executor.cc:299 
#8 0x00007fabd7864332 in gr_tpb_thread_body::gr_tpb_thread_body (this=0x7fabbbffed90, block=...) 
    at gr_tpb_thread_body.cc:49 
#9 0x00007fabd785cce7 in operator() (function_obj_ptr=...) at gr_scheduler_tpb.cc:42 
#10 operator() (function_obj_ptr=...) 
    at /home/tja/Research/energy/detector/gnuradio-3.3.0/gruel/src/include/gruel/thread_body_wrapper.h:49 
#11 boost::detail::function::void_function_obj_invoker0, void>::invoke (function_obj_ptr=...) at /usr/include/boost/function/function_template.hpp:153 
---Type to continue, or q to quit--- 
#12 0x00007fabd74914ef in operator() (this=) 
    at /usr/include/boost/function/function_template.hpp:1013 
#13 boost::detail::thread_data >::run (this=) 
    at /usr/include/boost/thread/detail/thread.hpp:61 
#14 0x00007fabd725ca55 in thread_proxy() from /usr/lib64/libboost_thread-mt.so.1.44.0 
#15 0x00000036b3e06d5b in start_thread() from /lib64/libpthread.so.0 
#16 0x00000036b3ae4a7d in clone() from /lib64/libc.so.6 
(gdb) 

ありがとう:

はここでGDBのバックトレースです!

答えて

11

Pythonは、何かがサブスレッドからコールバックしようとする前にメインスレッドによってある程度の初期化が行われることを期待しています。

メインスレッドがPythonを組み込んでいるアプリケーションの場合は、Py_Initialize()を呼び出した直後にPyEval_InitThreads()を呼び出す必要があります。

主スレッドがPythonインタプリタそのものであれば(ここのように)、マルチスレッド拡張モジュールを使用しているモジュールでは、サブスレッドの前にPyEval_InitThreads()が正しく呼び出されるように早期に「インポートスレッド」を含める必要があります産卵した。

+0

私が正しく理解していれば、 'import threading'で' PyEval_InitThreads'が自動的に呼び出されます。私はこの質問に非常に似た状況があります。ここでは、スレッドを生成し、そのコールバックを呼び出すCライブラリにコールバックを与えるPythonスクリプトがあります。私は 'PyGILState_Release'にsegfaultを取得し、あなたのアドバイスに従って' import sys'と 'import signal'の直後に' import threading'を追加しました。 segfaultは去っていませんでした。私はさらにPythonスクリプトで何かを呼び出す必要がありますか? – Shahbaz

+0

@Shahbaz: 'PyEval_InitThreads'を早期に呼び出すことができないのは、PythonのC拡張を書くときにsegfaultを引き起こす可能性がある多くの事の一つです。たとえば、segfaultはバグの参照の非常に一般的な症状です。また、 'PyGILState_Release'がスレッド状態をクリーンアップしているときにそれらが現れることは珍しいことではありません。 – ncoghlan

+0

お聞きします。実際、それを私のinit関数に追加することで問題は解決しました。あなたの最後の段落のために私はあなたに質問しました。私のモジュールを使用しているモジュールは 'Python_InitThreads'が呼び出されるように' import threading'を実行するべきです。しかし、私は 'PyEval_InitThreads'を自分でやる必要があります。 – Shahbaz

7

この正確な問題も同様に発生しました。 CPythonのスレッドに関係するもののドキュメントは、残念ながらうまくいきものではありません。

基本的に、あなたは次のことを実行する必要があります。

前に、他のスレッドが起動されているあなたのメインスレッドでは、あなたはPyEval_InitThreads()を呼び出す必要があります。これを行うには、PyInitialize()に電話をした直後に行ってください。

ここで、PyEval_InitThreads()は、Pythonインタープリタのスレッド状態を初期化するだけでなく、でもは、グローバルインタープリタロックを暗黙的に取得します。つまり、他のスレッドでPyGILEnsure_State()を呼び出す前にロックを解除する必要があります。そうしないと、プログラムがハングします。これは、関数PyEval_ReleaseLock()で行うことができます。任意の追加のスレッドで

PyInitialize(); 
PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

次に、あなたが言う必要があるのPython APIを使用して、いつでも:だから基本的に、あなたのメインスレッド、他のスレッドが起動される前に、あなたが言いたいので

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

/* ... some code that does things with Python ... */ 

PyGILState_Release(gstate); 
+1

[PyEval_ReleaseLock()は間違っています](http://bugs.python.org/issue1720250)。代わりに[PyEval_SaveThread/PyEval_RestoreThread](http://hg.python.org/cpython/file/5b0595339c9d/Include/ceval.h#l115)を使用することができます。 – jfs

+0

@ J.F.Sebastianあなたは理由を説明できますか? – Alex

+0

@windfinder:リンクを読んでください。 – jfs

関連する問題