从 C++ 调用 Python

Posted

技术标签:

【中文标题】从 C++ 调用 Python【英文标题】:Call Python from C++ 【发布时间】:2009-09-13 11:04:48 【问题描述】:

我正在尝试从我的主 C++ 程序调用 Python 脚本中的函数。 python 函数接受一个字符串作为参数并且不返回任何内容(ok.. 'None')。 只要在再次调用函数之前完成之前的调用,它就可以很好地工作(从未想过会那么容易..),否则在pModule = PyImport_Import(pName)会出现访问冲突。

有很多教程如何在 C 中嵌入 python,反之亦然,但我没有发现任何关于这个问题的内容。

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】:

当您说“只要在再次调用函数之前完成上一次调用”时,我只能假设您有多个线程从 C++ 调用到 Python。 python不是线程安全的,所以这会失败!

阅读 Python 手册中的全局解释器锁 (GIL)。也许以下链接会有所帮助:

http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock http://docs.python.org/c-api/init.html#PyEval_InitThreads http://docs.python.org/c-api/init.html#PyEval_AcquireLock http://docs.python.org/c-api/init.html#PyEval_ReleaseLock

***上提到了 GIL:

http://en.wikipedia.org/wiki/Global_Interpreter_Lock

【讨论】:

【参考方案2】:

感谢您的帮助!

是的,你是对的,有几个 C 线程。从没想过解释器本身需要互斥锁 - GIL 对我来说是一个全新的概念(甚至在整个教程中都没有提到)。

在阅读参考资料后(肯定不是其中最简单的部分,虽然 PyGILState_* 函数大大简化了整个事情),我添加了一个

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

函数来正确初始化解释器。 每个线程都创建自己的数据结构,获取锁并在之后释放它,如参考中所示。

正常工作,但是在终止进程之前调用 Py_Finalize() 时,我得到一个段错误.. 离开它有什么问题吗?

【讨论】:

很高兴这解决了您的问题。我想不出为什么你会在调用 Py_Finalize() 时遇到问题——也许你可以提供一个简化的例子来显示另一个问题中的问题。你真的应该彻底关闭 Python,但如果你只是要退出应用程序,你可能会没事......我强烈建议你找出它崩溃的原因。 @DanielPaull 能否为上述相同主题提供一个简单的工作示例。所以我很容易理解

以上是关于从 C++ 调用 Python的主要内容,如果未能解决你的问题,请参考以下文章

[转]Linux下Python与C++混合编程

pythonpython魔法方法(待填坑)

Head First PythonPython I/O

pythonpython操作剪切板-pyperclip模块

用于从 FORTRAN 代码调用的 C++ 函数调用 C++ 代码的 Cmake 配置文件

从 C++ 调用 python 函数时如何将 C++ 类作为参数传递?