2009-09-15 10 views
9

Ésta es una continuación de Call Python from C++Calling Py_Finalize() de C

Al inicio de la Programm que llamo la siguiente función para inicializar el intérprete:

void initPython(){ 
    PyEval_InitThreads(); 
    Py_Initialize(); 
    PyEval_ReleaseLock(); 
} 

Cada hilo crea su propia estructura de datos y adquiere la cerradura con:

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 
//call python API, process results 
PyGILState_Release(gstate); 

Más bien sencillo una vez entendido el GIL, pero el problema es que me sale un error de segmentación cuando se llama a Py_Finalize().

void exitPython(){ 
    PyEval_AcquireLock(); 
    Py_Finalize(); 
} 

La referencia es bastante dudosa sobre Py_Finalize() (o tal vez sólo estoy leyendo el camino equivocado) y no estoy seguro de si PyEval_AcquireLock() puede adquirir el bloqueo si hay algunos hilos activos y qué sucede si hay subprocesos activos cuando se llama a Py_Finalize().

De todos modos, obtengo un segfault incluso si estoy seguro de que todos los hilos han terminado su trabajo, pero solo si se creó al menos uno. P.ej. llamando a initPython() seguido de exitPython() no crea ningún error.

tan sólo pudiera ignorar el problema y esperar que el sistema operativo sabe lo que hace, pero yo prefere si podía averiguar lo que está pasando ..

Respuesta

7

Sí, toda la sección es bastante dudosa, pero creo que tengo mi error.

Tengo que guardar el PyThreadState al inicializar el intérprete y cambiar este estado cuando lo termine (no tengo idea de por qué necesito un ThreadState específico para llamar a Finalize, ¿no deberían funcionar todos los estados?)

de todas formas el ejemplo si otras personas consiguieron el mismo problema:

PyThreadState *mainstate; 

void initPython(){ 
    PyEval_InitThreads(); 
    Py_Initialize(); 
    mainstate = PyThreadState_Swap(NULL); 
    PyEval_ReleaseLock(); 
} 

void exitPython(){ 
    PyEval_AcquireLock(); 
    PyThreadState_Swap(mainstate); 
    Py_Finalize(); 
} 

el único problema con esto es, que pueda adquirir el bloqueo como cualquier otro hilo, incluso si todavía hay temas de trabajo. La API no menciona lo que ocurre cuando se invoca Finalize() mientras otros subprocesos siguen funcionando. Suena como el ejemplo perfecto de una condición de carrera ...

1

has necesitado comentando todo el 'trabajo' hecho en tus hilos? Reemplácelo con un bucle ocupado o un sueño o algo así. Eso ayudará a determinar si es el código de inicialización/apagado, o algo que realmente está haciendo con Python. Tal vez no esté configurando los subprocesos correctamente: hay muchas funciones específicas de subprocesos en la API C y no estoy seguro de cuáles necesita para garantizar un funcionamiento correcto.

+0

He comentado todo pero PyGILState_Ensure() y Release() y el error todavía se produce. Si los comento también, no hay ningún problema. – Voo

+0

En ese caso, supongo que hay algo sobre la administración de subprocesos que no se está haciendo correctamente. Desafortunadamente, la página relevante de C API con todas las funciones de subprocesos no es obvia en cuanto a cuál de esas llamadas necesita. – Kylotan

+0

Las "llamadas que necesita" la mayor parte del tiempo son 'Py_BEGIN_ALLOW_THREADS' y su contraparte. Esas son, a su vez, macros que usan 'PyEval_SaveThread()' y su contraparte. Entonces, si estuviera escribiendo algo como OP, seguiría ese ejemplo. – Kevin

1

También estoy recibiendo un problema similar al ejecutar scripts que contienen pyxhook desde diferentes hilos a través del intérprete incorporado.

No hay problema si se ejecuta una secuencia de comandos a la vez. El gancho se libera correctamente, pero si dos o más secuencias de comandos se ejecutan en paralelo, el enganche no se detiene. Aunque mis scripts volvieron correctamente y cancel() desde pyxhook también se devolvieron correctamente, creo que todavía se están ejecutando algunos hilos relacionados con xlib. Este problema pyxhook lo he resuelto manteniendo una bandera global para ver si pyxhook ya se está ejecutando y no reiniciando pyxhook de cada hilo.

Ahora con respecto Py_Finalize(), si pyxhook se reinicializa en cada hilo:

si no llamo PyEval_AcquireLock() y PyThreadState_Swap() antes de llamar Py_Finalize() termina en Linux, pero no en Win32. En Win32 hay un problema si no paso por PyEval_AcquireLock() y PyThreadState_Swap().

Por el momento, la solución temporal para mí es terminar de manera diferente en dos sistemas operativos diferentes.

Cuestiones relacionadas