从C++调用Python
我想在我的主C++程序中调用一个Python脚本里的函数。这个Python函数接收一个字符串作为参数,但不返回任何东西(好吧,返回的是'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;
}
2 个回答
1
谢谢你的帮助!
是的,你说得对,确实有几个C线程。我从没想过解释器本身也需要互斥锁——全局解释器锁(GIL)对我来说是个全新的概念(而且在整个教程中根本没有提到过)。
在阅读参考资料后(这绝对不是最简单的部分,尽管PyGILState_*函数让整个事情简单了很多),我添加了一个
void initPython(){
PyEval_InitThreads();
Py_Initialize();
PyEval_ReleaseLock();
}
函数来正确初始化解释器。每个线程都会创建自己的数据结构,获取锁,然后像参考资料中所示的那样释放锁。
这样做效果很好,但在进程结束前调用Py_Finalize()时,我遇到了段错误……如果不调用它会有什么问题吗?
5
当你说“只要上一个调用在函数再次被调用之前完成”,我只能猜测你是在说有多个线程从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: