11

更新まあ、PyGILState_Ensure()の呼び出しがトリックを実行する前に、PyEval_InitThreads()を追加するように見えます。急いで物事を理解するために、私は自分の「ぶら下がっている」をPyEval_InitThreads()に誤って帰した。

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

現在どのスレッド(存在する場合)がグローバルインタープリターロックを持っているかが不明な場合、この関数を呼び出すことは安全ではありません。


まず第一に、私はいくつかの変更されたGNU Radioコード、特に変更されたgr_bin_statistics_fブロックに取り組んでいます。さて、私の正確な状況をほぼ説明しているバグレポート(古いものですが)があります。

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

現在、バグレポートに記載されているusrp_spectrum_sense.pyはgr_bin_statistics_f(C ++)を呼び出し、その後定期的にPythonを呼び出してUSRP(無線)を再調整します。

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 Radioメーリングリストにメッセージを送信するときですか?

Fedora14x86_64でPython2.7を使用する。

GDBのバックトレースは次のとおりです。


(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) 

見てくれてありがとう!

4

2 に答える 2

13

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

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

メインスレッドが代わりにPythonインタープリター自体である場合(ここでの場合のように)、マルチスレッド拡張モジュールを使用するモジュールには、サブスレッドPyEval_InitThreads()が生成される前に正しく呼び出されるように、早期に「インポートスレッド」を含める必要があります。

于 2011-02-02T04:45:59.987 に答える
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); 
于 2011-02-12T02:19:54.537 に答える