Python PyGILState_ {Ensure/Release}在从Python代码返回C++时导致段错误

Mr.*_*nce 11 c++ python multithreading gnuradio segmentation-fault

更新好吧,看起来在调用PyGILState_Ensure()之前添加PyEval_InitThreads()就可以了.在我急于解决问题时,我错误地将我的"挂起"归因于PyEval_InitThreads().

但是,在阅读了一些Python文档后,我想知道这是否是正确的解决方案.

当未知哪个线程(如果有)当前具有全局解释器锁时,调用此函数是不安全的.


首先,我正在研究一些经过修改的GNU Radio代码 - 特别是修改过的gr_bin_statistics_f块.现在,有一个错误报告(虽然是一个旧报告)几乎描述了我的确切情况.

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

现在,bug报告中提到的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);
Run Code Online (Sandbox Code Playgroud)

因此,一旦我们从Python代码返回,当调用PyGILState_Release(d_gstate)时就会发生分段错误.虽然我的代码和原始的gr_bin_statistics_f之间存在差异,但似乎没有任何东西与此远程相关.

我读到在PyGILState_Ensure()之前调用PyEval_InitThreads()已经解决了一些人的问题,但它只是导致我的程序挂起.

任何人都可以为我阐明这一点吗?或者只是时候发送消息到GNU Radio邮件列表?

在Fedora 14 x86_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) 
Run Code Online (Sandbox Code Playgroud)

谢谢你的期待!

nco*_*lan 13

Python期望在尝试从子线程回调之前,主线程完成一定量的初始化.

如果主线程是嵌入Python的应用程序,那么它应该PyEval_InitThreads()在调用后立即调用Py_Initialize().

如果主线程是Python解释器本身(这里似乎就是这种情况),那么使用多线程扩展模块的模块应尽早包含"导入线程",以确保PyEval_InitThreads()在生成任何子线程之前正确调用.


Cha*_*via 8

我也遇到了这个问题.遗憾的是,关于CPython中线程的任何内容的文档都是不完整的.

基本上,您需要执行以下操作:

线程中,在生成任何其他线程之前,您需要调用PyEval_InitThreads().在你打电话之后,这是一个好地方PyInitialize().

现在,PyEval_InitThreads()不仅初始化Python解释器线程状态,它隐含取得全局解释器锁.这意味着,您需要在调用PyGILEnsure_State()其他线程之前释放锁定,否则您的程序将挂起.您可以使用该功能执行此操作PyEval_ReleaseLock().

所以基本上,在你的线程中,在启动任何其他线程之前,你想说:

PyInitialize();
PyEval_InitThreads();
PyEval_ReleaseLock();
Run Code Online (Sandbox Code Playgroud)

然后,在任何其他线程中,只要您使用Python API,您需要说:

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

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

PyGILState_Release(gstate); 
Run Code Online (Sandbox Code Playgroud)