2009-09-13 26 views
7

Estoy tratando de llamar a una función en un script de Python desde mi programa principal de C++. La función python toma una cadena como argumento y no devuelve nada (ok ... 'Ninguno'). Funciona perfectamente bien (nunca pensé que sería tan fácil ...) siempre y cuando la llamada anterior haya finalizado antes de volver a llamar a la función; de lo contrario, existe una infracción de acceso al pModule = PyImport_Import(pName).Llamar a Python desde C++

Hay muchos tutoriales sobre cómo incrustar Python en C y viceversa, pero no encontré nada sobre ese problema.

int callPython(TCHAR* title){ 
    PyObject *pName, *pModule, *pFunc; 
    PyObject *pArgs, *pValue; 

Py_Initialize(); 
    pName = PyUnicode_FromString("Main"); 
    /* Name of Pythonfile */ 

    pModule = PyImport_Import(pName); 
    Py_DECREF(pName); 

if (pModule != NULL) { 
     pFunc = PyObject_GetAttrString(pModule, "writeLyricToFile"); 
     /* function name. pFunc is a new reference */ 
     if (pFunc && PyCallable_Check(pFunc)) { 
      pArgs = PyTuple_New(1); 

    pValue = PyUnicode_FromWideChar(title, -1); 

    if (!pValue) { 
     Py_DECREF(pArgs); 
       Py_DECREF(pModule); 
     showErrorBox(_T("pValue is false")); 
     return 1; 
      } 
    PyTuple_SetItem(pArgs, 0, pValue); 

      pValue = PyObject_CallObject(pFunc, pArgs); 
      Py_DECREF(pArgs); 

      if (pValue != NULL) { 
       //worked as it should! 
       Py_DECREF(pValue); 
      } 
      else { 
       Py_DECREF(pFunc); 
       Py_DECREF(pModule); 
       PyErr_Print(); 
     showErrorBox(_T("pValue is null")); 
     return 1; 
      } 
     } 
     else { 
      if (PyErr_Occurred()) PyErr_Print(); 
      showErrorBox(_T("pFunc null or not callable")); 
     return 1; 
     } 
     Py_XDECREF(pFunc); 
     Py_DECREF(pModule); 
    } 
    else { 
     PyErr_Print(); 
     showErrorBox(_T("pModule is null")); 
    return 1; 
    } 
    Py_Finalize(); 
    return 0; 
} 

Respuesta

5

Cuando dice "siempre y cuando se termina la llamada anterior antes de la función se llama de nuevo", sólo puedo suponer que usted tiene múltiples hilos que llaman desde C++ en Python. El pitón no es seguro para subprocesos, ¡así que esto va a fallar!

Lectura en Global Interpreter Lock (GIL) en el manual de Python. Tal vez los siguientes enlaces ayudarán:

El GIL se menciona en la Wikipedia:

1

Gracias por su ayuda!

Sí, tiene razón, hay varios subprocesos en C. Nunca pensé que necesitaría mutex para el intérprete en sí; el GIL es un concepto completamente nuevo para mí (y ni siquiera se menciona una vez en todo el tutorial).

Después de leer la referencia (seguro que no es la parte más fácil de la misma, a pesar de las PyGILState_ * funciones simplifican todo el asunto mucho), he añadido una función

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

para inicializar el intérprete correctamente. Cada hilo crea su estructura de datos, adquiere el bloqueo y lo libera después como se muestra en la referencia.

Funciona como debería, pero cuando llamo a Py_Finalize() antes de terminar el proceso me sale un segfault ... ¿algún problema con simplemente dejarlo?

+2

Me alegro de que esto haya solucionado sus problemas. No puedo pensar por qué tendrías problemas para llamar a Py_Finalize(); quizás podrías proporcionar un ejemplo simplificado que muestre el problema en otra pregunta. Realmente debería cerrar Python limpiamente, pero si solo va a salir de la aplicación, podría estar bien ... Le sugiero que averigüe por qué falla. –

+0

@DanielPaull puede por favor dar un ejemplo de trabajo simple para el mismo tema anterior. Así que puedo entender fácilmente – lkkkk