2011-12-09 11 views
6

RISPOSTAPerché sta gettando PyGILState_Release errori con Python fatali

Ok, ho risolto questo problema. È tutto in come si inizializza lo stato del thread. Non è necessario utilizzare ReleaseLock. Basta aggiungere InitThreads chiamano alla definizione di modulo:

BOOST_PYTHON_MODULE(ModuleName) 
{ 
    PyEval_InitThreads(); 

    ... 
} 

Ok, ho cercato di diagnosticare questo problema per ore e versata attraverso quello che sembra ogni esempio sul web. Stanco ora, quindi potrei mancare qualcosa di ovvio ma ecco cosa sta succedendo:

Sto avvolgendo una libreria in boost python. Sto eseguendo uno script python che importa la lib, costruisce alcuni oggetti e quindi riceve callback da C++ che richiama in python. Prima di invocare chiamate su qualsiasi funzione python, cerco di acquisire il blocco dell'interprete globale. Ecco alcuni esempi di codice:

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 
    } 

    ... 
} 

Il metodo onData sull'oggetto di destinazione è chiamato dalla libreria come un callback. In Python, ereditiamo da PyTarget e implementiamo un altro metodo. Quindi usiamo call_method <> per chiamare quel metodo. gil_lock acquisisce il blocco e tramite RIAA garantisce che lo stato del thread acquisito è sempre l'unico rilascio e che viene infatti sempre rilasciato quando si esce dal campo di applicazione.

Tuttavia, quando lo eseguo in uno script che tenta di ottenere un numero elevato di callback su questa funzione, esso segnaults sempre. Script simile a questa:

# Initialize the library and setup callbacks 
... 

# Wait until user breaks 
while 1: 
    pass 

Inoltre, lo script python costruisce sempre un oggetto che viene eseguito:

PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

prima di ricevere qualsiasi callback.

Ho ridotto il codice a dove non sto nemmeno chiamando in python in onData, sto solo acquisendo il blocco. Al rilascio è sempre crash sia con:

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

o

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

È apparentemente casuale. Sono pazzo qui, perché sento che sto usando il blocco GIL correttamente, tuttavia non sembra funzionare affatto.

Altre note: Solo un thread chiama il metodo onData dell'oggetto Target.

Quando dormo nel ciclo while nel modulo python di chiamata con time.sleep(), sembra consentire lo script di funzionare più a lungo, ma alla fine lo script segfault con problemi simili. La quantità di tempo che dura è proporzionale alla quantità di tempo.sleep (cioè time.sleep (10) è più lungo di time.sleep (0.01). Questo mi fa pensare a come la sceneggiatura sta riacquistando il GIL senza il mio permesso

PyGILState_Release e PyGILState_Ensure non vengono chiamati dove altro nel mio codice, nessun altro dove deve essere chiamato in python.

Aggiornamento

Ho letto un'altra domanda che suggerisce import threading nel modulo come alternativa alla corsa

PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

Tuttavia, non sembra al lavoro quando ho importare filettatura prima del mio modulo e rimuovere le due righe precedenti dal mio wrapper boost python.

+1

Felice che tu l'abbia capito. Anche quello mi ha preso, quando. Cordiali saluti, puoi pubblicare una risposta alla tua stessa domanda. Ciò consentirà alle persone a cui piace la tua soluzione di votare. –

+0

Grazie, relativamente nuovo per lo stack overflow e ancora ottenere il blocco di esso. Pubblicherà. –

risposta

5

Ok, ho risolto questo problema. È tutto in come si inizializza lo stato del thread. Non è necessario utilizzare ReleaseLock. Aggiungi semplicemente la chiamata InitThreads alla definizione del tuo modulo:

BOOST_PYTHON_MODULE(ModuleName) 
{ 
    PyEval_InitThreads(); 

    ... 
} 
+0

grazie amico. mi ha aiutato. – genjix

Problemi correlati