tags:

views:

181

answers:

2

I'm trying to call a function in a Python script from my main C++ program. The python function takes a string as the argument and returns nothing (ok.. 'None'). It works perfectly well (never thought it would be that easy..) as long as the previous call is finished before the function is called again, otherwise there is an access violation at pModule = PyImport_Import(pName).

There are a lot of tutorials how to embed python in C and vice versa but I found nothing about that problem.

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;
}
+1  A: 

When you say "as long as the previous call is finished before the function is called again", I can only assume that you have multiple threads calling from C++ into Python. The python is not thread safe, so this is going to fail!

Read up on the Global Interpreter Lock (GIL) in the Python manual. Perhaps the following links will help:

The GIL is mentioned on Wikipedia:

Daniel Paull
A: 

Thank you for your help!

Yes you're right, there are several C threads. Never thought I'd need mutex for the interpreter itself - the GIL is a completly new concept for me (and isn't even once mentioned in the whole tutorial).

After reading the reference (for sure not the easiest part of it, although the PyGILState_* functions simplify the whole thing a lot), I added an

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

function to initialise the interpreter correctly. Every thread creates its data structure, acquires the lock and releases it afterwards as shown in the reference.

Works as it should, but when calling Py_Finalize() before terminating the process I get a segfault.. any problems with just leaving it?

Voo
I'm glad this has fixed your problems. I cant think why your would have problems calling Py_Finalize() - perhaps you could provide a simplified example that shows up the problem in another question. You really should shut down Python cleanly, but if you are just going to exit the app, you might be fine... I strongly suggest you work out why it crashes.
Daniel Paull