我正在编写一个调用python脚本的c ++类。但是当我调用该方法一秒钟时,它停止工作。我到处用谷歌搜索,没有找到任何线索。我以为是因为引用计数问题,所以我删除了所有Py_DECREF
呼叫,但仍然没有帮助。
这里是 c++ 代码(在原始代码中,我每次在 RunModel
中调用 PyObject_GetAttrString
,但在第二次调用 gdb 中表示第二个func
是<Py_NoneStruct>
。所以我改成了这个(:
#include <Python.h>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <thread>
using namespace std;
class PyRecognitionContext {
PyObject *module, *func, *result, *args;
public:
PyRecognitionContext(int argc, char **argv) {
Py_Initialize();
PySys_SetArgv(argc, argv);
module = PyImport_Import(PyString_FromString("model.t"));
if (module == NULL) {
PyErr_Print();
throw std::invalid_argument("fails to import the module");
}
}
~PyRecognitionContext() {
Py_Finalize();
}
void LoadModel(std::string model) {
func = PyObject_GetAttrString(module, "load");
args = PyTuple_New(1);
PyTuple_SetItem(args, 0, PyString_FromString(model.c_str()));
PyObject_CallObject(func, args);
func = PyObject_GetAttrString(module, "run");
}
char* RunModel(const char *imageBytes, size_t size) {
args = PyTuple_New(1);
PyTuple_SetItem(args, 0, PyByteArray_FromStringAndSize(imageBytes, size));
result = PyObject_CallObject(func, args);
char* resultStr = PyString_AsString(result);
return resultStr;
}
};
int task(PyRecognitionContext pr, string fileName) {
cout << "//";
cout << fileName << endl;
std::ifstream ifs(fileName, ios::binary|ios::ate);
size_t imgSize = ifs.tellg();
char *result = new char[imgSize];
ifs.seekg(0, ios::beg);
ifs.read(result, imgSize);
ifs.close();
std::cout << pr.RunModel(result, imgSize) << endl;
return 0;
}
int main(int argc, char *argv[]) {
PyRecognitionContext pr(argc, argv);
pr.LoadModel("/home/dickzhou/data/sex_256/cp/");
cout << "//loaded" << endl;
task(pr, "/home/dickzhou/data/face/male/24-28/24/135.JPG");
task(pr, "/home/dickzhou/data/face/female/24-28/24/138.JPG");
//thread t1(task, pr, "/home/dickzhou/data/face/male/24-28/24/135.JPG");
//thread t2(task, pr, "/home/dickzhou/data/face/female/24-28/24/125.JPG");
//t1.join();
//t2.join();
cout << "//done" << endl;
return 0;
}
我使用以下方法编译它:
g++ -I/usr/include/python2.7 -I/usr/include/python2.7 -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O1 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -lpthread -ldl -lutil -lm -lpython2.7 -Xlinker -export-dynamic -std=c++11 pdr.cpp
这是我的 GDB 输出:
(gdb) break 40
Breakpoint 1 at 0x401f47: file pdr.cpp, line 40.
(gdb) run
Starting program: /home/dickzhou/data/sex_256/c++/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
//loaded
///home/dickzhou/data/face/male/24-28/24/135.JPG
Breakpoint 1, RunModel (size=14637, imageBytes=0x6e5270 "377330377", <incomplete sequence 340>, this=0x7fffffffe040) at pdr.cpp:40
40 result = PyObject_CallObject(func, args);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-105.el7.x86_64 libgcc-4.8.5-16.el7.x86_64 libstdc++-4.8.5-4.el7.x86_64 python-libs-2.7.5-34.el7.x86_64
(gdb) p func
$1 = (PyObject *) 0x2aaaaabfa9b0
(gdb) p args
$2 = (PyObject *) 0x2aaaaabf2d10
(gdb) c
Continuing.
a
///home/dickzhou/data/face/female/24-28/24/138.JPG
Breakpoint 1, RunModel (size=13572, imageBytes=0x68d9f0 "377330377", <incomplete sequence 340>, this=0x7fffffffe040) at pdr.cpp:40
40 result = PyObject_CallObject(func, args);
(gdb) p func
$3 = (PyObject *) 0x2aaaaabfa9b0
(gdb) p args
$4 = (PyObject *) 0x2aaaaab8bbd0
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00002aaaab33c09a in PyObject_Call () from /lib64/libpython2.7.so.1.0
(gdb)
最小的 Python 代码是:
def load(str):
pass
def run(bytes):
return "a"
您的实际问题不是遵循零法则。您有一个包含手动管理的资源(资源是以后需要释放的任何内容(的类。那不行。
PyRecognitionContext
的实例被复制,Py_Finalize()
被调用两次,而且是过早的。
全局 Python 上下文需要初始化和完成。我们可以将其委托给一个单独的类,以促进单一责任原则。
struct PyContext
{
PyContext()
{
Py_Initialize();
}
~PyContext()
{
Py_Finalize();
}
PyContext& operator=(const PyContext&) = delete;
PyContext(const PyContext&) = delete;
PyContext& operator=(PyContext&&) = delete;
PyContext(PyContext&&) = delete;
};
现在,您可以将该类的成员放入 PyRecognitionContext 中
class PyRecognitionContext {
PyContext pyContext;
// ... rest of the code
};
这会将运行时错误移动到编译时。
其他 Python 对象也是资源,因为它们需要释放。我们可以将std::unique_ptr
与自定义删除器一起使用来管理这些。
感谢您的所有帮助,我已经解决了这个问题。
问题是解构函数被调用了两次,因为task
函数是按值传递的。我将其更改为按引用传递:
int task(PyRecognitionContext *pr, string fileName) {
cout << "//";
cout << fileName << endl;
std::ifstream ifs(fileName.c_str(), ios::binary|ios::ate);
size_t imgSize = ifs.tellg();
char *result = new char[imgSize];
ifs.seekg(0, ios::beg);
ifs.read(result, imgSize);
ifs.close();
std::cout << pr->RunModel(result, imgSize) << endl;
return 0;
}