How can I start a Python thread FROM C++?

1k views Asked by At

Note that I'm constrained to use Python 2.6. I have a Python 2.6 application that uses a C++ multi-threaded API library built with boost-python. My use-case was simply to execute a Python function callback from a C++ boost thread but despite the many different attempts and researching all the available online resources I haven't found any way that works. All the proposed solutions revolve around a different combination of the functions: Py_Initialize*, PyEval_InitThreads, PyGILState_Ensure, PyGILState_Release but after trying all possible combinations nothing works in practice e.g.

Therefore, this question: how can I start and run a Python thread from C++? I basically want to: create it, run it with a Python target function object and forget about it.

Is that possible?

3

There are 3 answers

0
SkyWalker On BEST ANSWER

The answer to the OP How to call Python from a boost thread? also answers this OP or DP (Derived:)). It clearly demonstrates how to start a thread from C++ that callbacks to Python. I have tested it and works perfectly though needs adaptation for pre-C++11. It uses Boost Python, is indeed an all inclusive 5* answer and the example source code is here.

0
otorrillas On

Based on the text below from your question:

Run a Python thread from C++? I basically want to: create it, run it with a Python target function object and forget about it.

You may find useful to simply spawn a process using sytem:

system("python myscript.py")

And if you need to include arguments:

string args = "arg1 arg2 arg3 ... argn"
system("python myscript.py " + args)
6
pat On

You should call PyEval_InitThreads from your init routine (and leave the GIL held). Then, you can spawn a pthread (using boost), and in that thread, call PyGILState_Ensure, then call your python callback (PyObject_CallFunction?), release any returned value or deal with any error (PyErr_Print?), release the GIL with PyGILState_Release, and let the thread die.

void *my_thread(void *arg)
{
    PyGILState_STATE gstate;
    PyObject *result;

    gstate = PyGILState_Ensure();

    if ((result = PyObject_CallFunction(func, NULL))) {
        Py_DECREF(result);
    }
    else {
        PyErr_Print();
    }

    PyGILState_Release(gstate);

    return NULL;
}