2011-12-09 1 views
6

나는이 문제를 해결,왜 PyGILState_Release가 던지고 치명적인 파이썬 오류

이 좋아 대답했다. 스레드 상태를 초기화하는 방법은 모두. 당신은 ReleaseLock을 전혀 사용할 필요가 없습니다. 간단히 InitThreads이 모듈 정의에 전화를 추가

BOOST_PYTHON_MODULE(ModuleName) 
{ 
    PyEval_InitThreads(); 

    ... 
} 

좋아, 나는 시간 동안이 문제를 진단하는 것을 시도하고, 웹에있는 모든 예처럼 보이는 통해 부어있다. 이제 피곤해지기 때문에 뭔가 확실한 것을 놓치고 있을지 모르지만 여기에 무슨 일이 일어나고 있는지 알고 싶습니다.

라이브러리를 부스트 파이썬에 배치했습니다. 내가 lib를 가져오고, 일부 객체를 구성한 다음 파이썬으로 다시 호출하는 C++에서 콜백을받는 파이썬 스크립트를 실행 중입니다. 파이썬 함수를 호출하기 전에 전역 인터프리터 잠금을 얻으려고합니다. 다음은 몇 가지 샘플 코드입니다.

class ScopedGILRelease 
{ 
public: 
    inline ScopedGILRelease() 
    { 
     d_gstate = PyGILState_Ensure(); 
    } 

    inline ~ScopedGILRelease() 
    { 
     PyGILState_Release(d_gstate); 
    } 

private: 
    PyGILState_STATE d_gstate; 
}; 

class PyTarget : public DingoClient::ClientRequest::Target, public wrapper<DingoClient::ClientRequest::Target> 
{ 
    public: 
    PyTarget(PyObject* self_) : self(self_) {} 
    ~PyTarget() { 
     ScopedGILRelease gil_lock; 
    } 
    PyObject* self; 

    void onData(const boost::shared_ptr<Datum>::P & data, const void * closure) 
    { 
     ScopedGILRelease gil_lock; 
     // invoke call_method to python 
    } 

    ... 
} 

대상 객체의 onData 메서드는 라이브러리에서 콜백으로 호출됩니다. 파이썬에서는 PyTarget을 상속 받아 다른 방법을 구현합니다. 그런 다음 call_method <>을 사용하여 해당 메소드를 호출합니다. gil_lock은 잠금을 획득하고 RIAA를 통해 획득 한 스레드 상태가 항상 하나의 릴리스이며 범위를 벗어날 때 항상 해제된다는 것을 보장합니다.

그러나이 함수에서 많은 콜백을 얻으려고 시도하는 스크립트에서이 코드를 실행하면 항상 segfaults가됩니다.

PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

어떤 콜백을 받기 전에 :

# Initialize the library and setup callbacks 
... 

# Wait until user breaks 
while 1: 
    pass 

또한, 파이썬 스크립트를 항상 실행 객체가 구축 : 스크립트는 다음과 같이 보인다.

코드를 onData에서 파이썬으로 호출하지 않는 위치로 코드를 줄였습니다. 이제 막 잠금을 얻고 있습니다. 릴리스는 와 항상 충돌 중 하나

Fatal Python error: ceval: tstate mix-up 
Fatal Python error: This thread state must be current when releasing 

또는

Fatal Python error: ceval: orphan tstate 
Fatal Python error: This thread state must be current when releasing 

그것은 겉으로는 무작위입니다. 내가 GIL 자물쇠를 올바르게 사용하고있는 것처럼 느껴지기 때문에 나는 여기 미쳤다. 그러나 전혀 작동하지 않는 것 같다.

기타 참고 사항 : 하나의 스레드 만 대상 개체의 onData 메서드를 호출합니다.

time.sleep() 호출 파이썬 모듈에서 while 루프를 사용하면 스크립트가 더 오래 실행될 수 있지만 결국 스크립트는 유사한 문제로 segfault를 발생시킵니다. 스크립트의 지속 시간은 time.sleep (즉, time.sleep (10)이 time.sleep (0.01)보다 오래 실행 됨)에 비례합니다. 이렇게하면 내 허가없이 스크립트가 GIL을 다시 획득하는 방법을 생각할 수 있습니다

PyGILState_Release와 PyGILState_Ensure는 다른 곳에서는 파이썬으로 호출해야하는 곳이 아니라고합니다.

내가 전에 스레딩 가져올 때 작동하려면이 표시되지 않습니다

PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

그러나 실행에 대안으로 모듈에서 수입 스레딩을 제안 또 다른 질문을 읽었습니다

업데이트 내 모듈과 내 부스트 파이썬 래퍼에서 위의 두 줄을 제거하십시오.

+1

당신이 알아 낸 것을 기쁘게 생각합니다. 나도 그걸 가지고있어. 참고로, 자신의 질문에 대한 답변을 게시 할 수 있습니다. 그러면 솔루션을 좋아하는 사람들이 투표를 할 수 있습니다. –

+0

감사합니다. 상대적으로 스택 오버플로가 새롭고 여전히 중단되었습니다. 게시 할 예정입니다. –

답변

5

좋아,이 문제를 해결했습니다. 스레드 상태를 초기화하는 방법은 모두. 당신은 ReleaseLock을 전혀 사용할 필요가 없습니다. InitThreads 호출을 모듈 정의에 추가하기 만하면됩니다.

BOOST_PYTHON_MODULE(ModuleName) 
{ 
    PyEval_InitThreads(); 

    ... 
} 
+0

고마워. 도와 줬어. – genjix