我试图在C ++下调用Python中的函数。
这是我的尝试:
void myFuncion()
{
PyObject* fExportar = nullptr;
PyObject* modulo = nullptr;
PyObject* pName = nullptr;
const char *scriptDirectoryName = "path/of/my/pyfile";
Py_Initialize();
PyObject *sysPath = PySys_GetObject("path");
PyObject *path = PyUnicode_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
if (result == 0 )//0 if ok, -1 if error
{
pName = PyUnicode_FromString("exportarXLS");//exportarXLS.py
modulo = PyImport_Import(pName);
Py_DECREF(path);
if (modulo)
{
fExportar = PyObject_GetAttrString(modulo, "exportar");//it crahs here
Py_DECREF(modulo);
if (fExportar)
{
//call the function
}
}
}
else
{
PyErr_Print();
}
Py_Finalize();
}
}
问题是如果python脚本有任何错误的import
,我的C ++程序崩溃。在这种情况下,我怀疑我试图使用无效版本的PyQt4。
这是模块:(exportarXLS.py)
#!/usr/bin/python3
from PyQt4 import QtCore, QtGui, QtSql
def exportar():
print ("hello, I am probing")
现在我的问题:
现在我开始探索开发加载python插件函数的步骤,我想知道如果有人想要添加错误的import
脚本,我将如何避免崩溃
我也尝试将问题线包含在try/catch
块中,但它不起作用。
编辑:
我忘了说它只发生在我的Qt项目中如果我试图运行我的功能,我可以加载模块的错误,但它不会崩溃。我编辑了这篇文章
鸭胶带解决方案:
void signal_handler(int signal)
{
std::cout << "Usefull information" std::endl;
exit(1);
}
...
std::signal(SIGSEGV, signal_handler);
Doc:https://en.cppreference.com/w/cpp/utility/program/signal
我认为这种解决方案只能在调试中使用
最好通过找出SEGV的根本原因来处理问题,因为应用程序的状态可能会因触发而严重损坏。
如果你想尝试以半结构化的方式捕获SEGV,那么你可以使用类似示例代码的东西,它使用sigsetjmp
和siglongjmp
:
#include <python3.7m/Python.h> // That's my python
#include <setjmp.h>
#include <signal.h>
static sigjmp_buf env;
static void
catch_segv(int func)
{
siglongjmp(env, 1);
}
int myFunction()
{
PyObject* fExportar = nullptr;
PyObject* modulo = nullptr;
PyObject* pName = nullptr;
const char *scriptDirectoryName = "."; // NOTE: I changed the path for me
Py_InitializeEx(1); // NOTE: skip signal handlers being registered - for embedding
PyObject *sysPath = PySys_GetObject("path");
PyObject *path = PyUnicode_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
if (result == 0 )//0 if ok, -1 if error
{
pName = PyUnicode_FromString("beep");//exportarXLS.py
modulo = PyImport_Import(pName);
Py_DECREF(path);
if (modulo)
{
// redirect segv handler here:
sig_t old = signal(SIGSEGV, catch_segv);
// record an environment to return to with siglongjmp
if (sigsetjmp(env, 1)) { // returns 0 on setting up, 1 when called with siglongjmp(env, 1)
// handler called
Py_Finalize();
signal(SIGSEGV, old); // restore old handler
return 1; // return to caller
} else {
// this triggers a segv (for the test)
(reinterpret_cast<sig_t>(0))(1);
fExportar = PyObject_GetAttrString(modulo, "beep");//it crahs here
Py_DECREF(modulo);
if (fExportar)
{
//call the function
}
}
signal(SIGSEGV, old); // restore old handler
}
}
else
{
PyErr_Print();
}
Py_Finalize();
return 0; // return success.
}
int main(int argc, char **argv)
{
return myFunction();
}
这个问题听起来很熟悉,我甚至可以用你的代码重现它:
如果不止一次调用myFunction(),会发生多次导入模块的情况。根据文件,这可能会导致问题:
“如果多次调用初始化例程,有些扩展可能无法正常工作;如果应用程序多次调用Py_Initialize()和Py_Finalize(),就会发生这种情况。” https://docs.python.org/2/c-api/init.html
因此,如果您的应用中出现这种情况,则解决方法是仅初始化Python解释器一次:
#include <iostream>
#include <Python/Python.h>
void myFuncion()
{
PyObject* fExportar = nullptr;
PyObject* modulo = nullptr;
PyObject* pName = nullptr;
const char *scriptDirectoryName = "path/of/my/pyfile";
PyObject *sysPath = PySys_GetObject("path");
PyObject *path = PyUnicode_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
if (result == 0 )//0 if ok, -1 if error
{
pName = PyUnicode_FromString("exportarXLS");//exportarXLS.py
modulo = PyImport_Import(pName);
Py_DECREF(path);
if (modulo)
{
fExportar = PyObject_GetAttrString(modulo, "exportar");//it crahs here
Py_DECREF(modulo);
if (fExportar)
{
//call the function
}
}
}
else
{
PyErr_Print();
}
}
int main(int argc, const char * argv[]) {
Py_Initialize();
myFuncion();
myFuncion();
// what ever
Py_Finalize();
return 0;
}
编辑:“我甚至可以重现它”,这意味着我可以通过导入numpy在另一条线上让它崩溃。