2011-02-01 3 views
11

업데이트 PyGILState_Ensure() 호출이 트릭을 수행하기 전에 PyEval_InitThreads()를 추가하는 것처럼 보입니다. 내 상황을 파악하는 서둘러, 내 "매달리기"를 PyEval_InitThreads()에 잘못 지정했습니다.Python PyGILState_ {보장/해제}는 Python 코드에서 C++로 돌아 오는 동안 segfault를 발생시킵니다.

그러나 파이썬 설명서를 읽은 후에 이것이 올바른 해결책인지 궁금합니다.

현재 전역 인터프리터 잠금이있는 스레드 (있는 경우)를 알 수없는 경우이 함수를 호출하는 것은 안전하지 않습니다. 특히 수정 된 gr_bin_statistics_f 블록 - 모든


첫째, 나는 약간의 수정 GNU 라디오 코드 작업입니다. 지금, 나의 정확한 상황을 거의 묘사하는 버그 리포트가있다.

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

이제 버그 보고서에 언급 usrp_spectrum_sense.py 다음 USRP (라디오) 조정을 다시 주기적으로 파이썬을 호출 (C++) gr_bin_statistics_f를 호출합니다.

다음은 파이썬 코드를 호출 할 때 발생하는 것입니다 :

PyGILState_STATE d_gstate; 
d_gstate = PyGILState_Ensure(); 

// call python code 

PyGILState_Release(d_gstate); 

그래서, 우리는 파이썬 코드에서 반환하면 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

파이썬은 서브 스레드에서 콜백을 시도하기 전에 메인 스레드가 일정량의 초기화를 수행 할 것으로 예상합니다.

주 스레드가 파이썬을 포함하고있는 응용 프로그램 인 경우 Py_Initialize()을 호출 한 직후에 PyEval_InitThreads()을 호출해야합니다.

주 스레드가 파이썬 인터프리터 (대신 여기에있는 것처럼 보임) 인 경우 다중 스레드 확장 모듈을 사용하는 모듈은 하위 스레드가 나오기 전에 PyEval_InitThreads()이 올바르게 호출되도록 "가져 오기 스레드"를 초기에 포함해야합니다 산란한다.

+0

'import threading'에서 올바르게 이해하면 'PyEval_InitThreads'가 자동으로 호출됩니다. 맞습니까? 이 질문에 아주 비슷한 상황이 있습니다. 파이썬 스크립트에서 스레드를 생성하고 해당 콜백을 호출하는 C 라이브러리에 콜백을 제공합니다. 'PyGILState_Release'에 segfault를 얻었고 조언에 따라'import sys'와'import signal '바로 뒤에'import threading'을 추가했습니다. segfault는 떠나지 않았다. 파이썬 스크립트에서 뭔가를 추가로 호출해야합니까? – Shahbaz

+0

@Shahbaz :'PyEval_InitThreads'를 조기에 호출하지 못하면 Python 용 C 확장을 작성할 때 segfault를 일으킬 수있는 많은 것들 중 하나 일뿐입니다. 예를 들어, segfault는 버그를 참조하는 매우 일반적인 증상이며 'PyGILState_Release'가 스레드 상태를 정리할 때 segfault가 나타나기는 드문 일이 아닙니다. – ncoghlan

+0

나는 당신의 말을 듣는다. 사실, 그것을 내 init 함수에 추가하면 문제가 해결됩니다. 나는 마지막 단락 때문에 모듈을 사용하는 모듈이'import threading'을해서'PyEval_InitThreads'가 호출되어야한다고 말했습니까? 하지만 어쨌든'PyEval_InitThreads'를 할 필요가있는 것 같습니다. – Shahbaz

7

이 정확한 문제도 발생했습니다. CPython의 쓰레드와 관련한 문서는 불행히도 잘 모름니다.

은 기본적으로 다음을 수행해야합니다 귀하의 주요 스레드에서

, 다른 스레드가 산란되어, 당신은 PyEval_InitThreads()를 호출해야합니다. 이 작업을 수행 할 수있는 좋은 장소는 PyInitialize()으로 전화 한 직후입니다.

이제 PyEval_InitThreads()은 파이썬 인터프리터 스레드 상태를 초기화 할뿐만 아니라 으로 전역 적 인터프리터 잠금을 암시 적으로 획득합니다. 즉, 다른 스레드에서 PyGILEnsure_State()을 호출하기 전에 잠금을 해제해야합니다. 그렇지 않으면 프로그램이 중지됩니다. 이 작업은 PyEval_ReleaseLock() 함수를 사용하여 수행 할 수 있습니다.

다른 스레드가 시작되기 전에

그래서 기본적으로, 당신의 주요 스레드에서, 당신이 말하고 싶은 :

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

그런 다음, 추가 스레드에서, 언제 당신이 말할 필요가 파이썬 API를 사용 :

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

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

PyGILState_Release(gstate); 
+1

[PyEval_ReleaseLock() is incorrect] (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

관련 문제