2012-09-14 13 views
7

Estoy muy confundido sobre cómo exactamente puedo garantizar la seguridad de las hebras cuando llamo a un código Python desde un hilo C (o C++).Llamando al código de Python desde un hilo en C

El Python documentation parece estar diciendo que el idioma habitual de hacerlo es:

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

/* Perform Python actions here. */ 
result = CallSomeFunction(); 
/* evaluate result or handle exception */ 

/* Release the thread. No Python API allowed beyond this point. */ 
PyGILState_Release(gstate); 

Y de hecho, esta stackoverflow answer parece confirmar tanto. Pero un comentarista (con una reputación muy alta) dice lo contrario. El comentarista dice que debe usar PyEval_RestoreThread()/PyEval_SaveThread().

Los documentos parecen confirmar esto:

PyThreadState* PyEval_SaveThread() 

Release the global interpreter lock (if it has been created and 
thread support is enabled) and reset the thread state to NULL, 
returning the previous thread state (which is not NULL). If the lock 
has been created, the current thread must have acquired it. (This 
function is available even when thread support is disabled at compile 
time.) 

void PyEval_RestoreThread(PyThreadState *tstate) 

Acquire the global interpreter lock (if it has been created and thread 
support is enabled) and set the thread state to tstate, which must not 
be NULL. If the lock has been created, the current thread must not have 
acquired it, otherwise deadlock ensues. (This function is available even 
when thread support is disabled at compile time.) 

La forma en que los documentos describen esto, parece que PyEval_RestoreThread()/PyEval_SaveThread() es básicamente un lenguaje de exclusión mutua de bloqueo/desbloqueo. Por lo tanto, tendría sentido que antes de llamar a cualquier código de Python desde C, primero necesite bloquear el GIL y luego desbloquearlo.

Entonces, ¿cuál es? En la llamada de Python desde C, debería utilizar:

PyGILState_Ensure()/PyGILState_Release()

o

PyEval_RestoreThread/PyEval_SaveThread?


¿Y cuál es realmente la diferencia?

Respuesta

6

En primer lugar, casi nunca desea llamar al PyEval_RestoreThread/PyEval_SaveThread. En su lugar, desea llamar a las macros contenedoras Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS. El documentation está escrito para esas macros, por lo que no pudo encontrarlo.

De todos modos, de cualquier manera, no utiliza las funciones de subprocesos/macros para adquirir el GIL; los usas para liberar temporalmente el GIL cuando lo hayas adquirido.

Entonces, ¿por qué querrías hacer esto alguna vez? Bueno, en casos simples no lo haces; solo necesita Ensure/Release. Pero a veces necesitas mantener tu estado de subproceso de Python hasta más tarde, pero no necesitas mantener el GIL (o incluso explícitamente necesitar no mantener el GIL, para permitir que otro subproceso progrese, de modo que pueda señalizarte) Como lo explican los documentos, las razones más comunes para esto son la E/S de archivos o el cálculo extensivo de CPU.

Por último, ¿hay algún caso en el que desee llamar a las funciones en lugar de a las macros? Sí, si quieres acceder al PyHhreadState escondido. Si no puede pensar en una razón por la que podría querer eso, probablemente no tenga uno.

Cuestiones relacionadas