Python PyGILState_ {Ensure / Release}导致segfault,同时从Python代码返回到C ++ [英] Python PyGILState_{Ensure/Release} causes segfault while returning to C++ from Python code

查看:247
本文介绍了Python PyGILState_ {Ensure / Release}导致segfault,同时从Python代码返回到C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UPDATE 好吧,它看起来像添加PyEval_InitThreads()之前调用PyGILState_Ensure()做的伎俩。在我急于搞清楚这些事情我错误地归咎于我挂到PyEval_InitThreads()。



不过,读了一些Python文档我想知道如果这是正确的解决方案后,


当未知哪个线程(如果有)当前具有全局解释器锁时,调用此函数是不安全的。首先,我正在处理一些修改的GNU无线电代码 - 特别是一个修改的gr_bin_statistics_f块。现在,有一个错误报告(虽然是一个旧的),几乎描述了我的确切情况。



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



现在,我们提到usrp_spectrum_sense.py在错误报告中调用gr_bin_statistics_f(C ++),然后定期调用Python来重新调整USRP(radio)。



这里是当Python代码调用:

  PyGILState_STATE d_gstate; 
d_gstate = PyGILState_Ensure()

//调用python代码

PyGILState_Release(d_gstate);

因此,一旦从Python代码返回,当调用PyGILState_Release(d_gstate)时会出现分段错误。虽然有我的代码和原始gr_bin_statistics_f之间的差异,似乎没有任何可以远程与此有关。



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



任何人可以为我照亮这个吗?



在Fedora 14 x86_64上使用Python2.7。



这里是GDB回溯跟踪:

  
(gdb)c
继续。
[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)]

编程接收到的信号SIGSEGV,分段故障。
[切换到线程0x7fabbbfff700(LWP 23976)]
0x00000036b3e0db00在sempost()从/lib64/libpthread.so.0
(gdb)bt
#0 0x00000036b3e0db00在sem_post )from /lib64/libpthread.so.0
#1 0x00000036c1317679在PyThread_release_lock()从/usr/lib64/libpython2.7.so.1.0
#2 0x00007fabd6159c1f在〜ensure_py_gil_state(this = 0x2dc6fc0,x =上gnuradio_swig_py_general.cc:5593
#8.87亿)
3 gr_py_feval_dd :: calleval(此= 0x2dc6fc0,X = 8.87亿)的gnuradio_swig_py_general.cc:5605
#4 0x00007fabd77c4b6e gr_noise_level_f :: tune_window (此= 0x2db3ca0,
target_freq =)在gr_noise_level_f.cc:97
#5 0x00007fabd77c554b在gr_noise_level_f ::工作(这= 0x2db3ca0,noutput_items = 7,
input_items =,= output_items)
。在gr_noise_level_f.cc:115
#6 0x00007fabd7860714在gr_sync_block :: general_work(此= 0x2db3ca0,
noutput_items =,= ninput_items,
input_items =,= output_items)的gr_sync_block.cc :64
#7 0x00007fabd7846ce4在gr_block_executor :: run_one_iteration(此= 0x7fabbbffed90)
。在gr_block_executor.cc:299
#8 0x00007fabd7864332在gr_tpb_thread_body :: gr_tpb_thread_body(此= 0x7fabbbffed90,块= .. 。)
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
---类型继续,或者q退出---
#12 0x00007fabd74914ef in operator()(this =)
at /usr/include/boost/function/function_template.hpp:1013
#13 boost :: detail :: thread_data> :: run (this =)
在/usr/include/boost/thread/detail/thread.hpp:61
#14 0x00007fabd725ca55在thread_proxy()从/usr/lib64/libboost_thread-mt.so.1.44。 0
#15 0x00000036b3e06d5b in /lib64/libpthread.so.0
#15 0x00000036b3e6d5b在clone()中,来自/lib64/libc.so.6
(gdb)

感谢您的查找!

解决方案

Python希望在任何尝试从子线程回调之前,由主线程完成一定量的初始化。



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



如果主线程,而不是Python解释器本身(如似乎这里是这种情况),然后使用多线程扩展模块该模块应包括进口线程早确保PyEval_InitThreads()被调用正确的子线程产卵前。


UPDATE Well, it looks like adding PyEval_InitThreads() before the call to PyGILState_Ensure() does the trick. In my haste to figure things out I incorrectly attributed my "hanging" to PyEval_InitThreads().

However, after reading some Python documentation I am wondering if this is the correct solution.

It is not safe to call this function when it is unknown which thread (if any) currently has the global interpreter lock.


First of all, I am working on some modified GNU Radio code - particularly a modified gr_bin_statistics_f block. Now, there is a bug report (albeit an old one) which pretty much describes my exact situation.

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

Now, usrp_spectrum_sense.py which is mentioned in the bug report calls gr_bin_statistics_f (C++) which then calls back to Python periodically to re-tune the USRP (radio).

Here is what happens when the Python code is called:

PyGILState_STATE d_gstate;
d_gstate = PyGILState_Ensure();

// call python code

PyGILState_Release(d_gstate);

So, once we return from the Python code a segmentation fault occurs when PyGILState_Release(d_gstate) is called. While there are differences between my code and the original gr_bin_statistics_f, nothing seems to be remotely related to this.

I read that calling PyEval_InitThreads() before PyGILState_Ensure() has solved the problem for some people, but it just causes my program to hang.

Can anyone shed light on this for me? Or is it simply time to send a message to the GNU Radio mailing list?

Using Python2.7 on Fedora 14 x86_64.

Here is the GDB backtrace:


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

Thanks for looking!

解决方案

Python expects a certain amount of initialisation to be done by the main thread before anything attempts to call back in from a subthread.

If the main thread is an application that is embedding Python, then it should call PyEval_InitThreads() immediately after calling Py_Initialize().

If the main thread is instead the Python interpreter itself (as seems to be the case here), then the module using the multithreaded extension module should include an "import threading" early to ensure that PyEval_InitThreads() is called correctly before any subthreads are spawned.

这篇关于Python PyGILState_ {Ensure / Release}导致segfault,同时从Python代码返回到C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆