概述
在多线程开发中,往往会涉及很多handle、对象等变量的存储,这时候对于Python代码,我们可以采用面向对象编程。下面主要讲述C/C++如何调用Python类。
先看一段Python代码
student.py
class Person:
def __init__(self):
self.info = []
def push(self, name, sex, age):
self.info.append((name, sex, age))
def show(self):
print(self.info)
调用上述Python的C++代码
Person.hpp
#ifndef __PERSON_HPP__
#define __PERSON_HPP__
#include <Python.h>
#define LOG_DEBUG(msg, ...) printf("[%s][%s][%s][%d]: "msg, __TIME__, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
class Person
{
public:
PyObject* m_pDict = NULL;
PyObject* m_pHandle = NULL;
public:
Person();
~Person();
void Push(char *name, char *sex, int age);
void Show();
};
#endif
Person.cpp [1][2]
#include "Person.hpp"
Person::Person()
{
PyObject* pFile = NULL;
PyObject* pModule = NULL;
PyObject* pClass = NULL;
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //申请获取GIL
Py_BEGIN_ALLOW_THREADS;
Py_BLOCK_THREADS;
do
{
#if 0
Py_Initialize();
if (!Py_IsInitialized())
{
printf("Py_Initialize error!\n");
break;
}
#endif
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
pFile = PyString_FromString("student");
pModule = PyImport_Import(pFile);
if (!pModule)
{
printf("PyImport_Import student.py failed!\n");
break;
}
m_pDict = PyModule_GetDict(pModule);
if (!m_pDict)
{
printf("PyModule_GetDict student.py failed!\n");
break;
}
pClass = PyDict_GetItemString(m_pDict, "Person");
if (!pClass || !PyCallable_Check(pClass))
{
printf("PyDict_GetItemString Person failed!\n");
break;
}
m_pHandle = PyInstance_New(pClass, NULL, NULL);
if (!m_pHandle)
{
printf("PyInstance_New Person failed!\n");
break;
}
} while (0);
if (pClass)
Py_DECREF(pClass);
//if (m_pDict)
// Py_DECREF(m_pDict);
if (pModule)
Py_DECREF(pModule);
if (pFile)
Py_DECREF(pFile);
Py_UNBLOCK_THREADS;
Py_END_ALLOW_THREADS;
PyGILState_Release(gstate);
printf("Person::Person() end!\n");
}
Person::~Person()
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //申请获取GIL
Py_BEGIN_ALLOW_THREADS;
Py_BLOCK_THREADS;
if (m_pHandle)
Py_DECREF(m_pHandle);
if (m_pDict)
Py_DECREF(m_pDict);
Py_UNBLOCK_THREADS;
Py_END_ALLOW_THREADS;
PyGILState_Release(gstate);
#if 0
Py_Finalize();
#endif
printf("Person::~Person() end!\n");
}
void Person::Push(char *name, char *sex, int age)
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //申请获取GIL
Py_BEGIN_ALLOW_THREADS;
Py_BLOCK_THREADS;
do
{
PyObject_CallMethod(m_pHandle, "push", "ssi", name, sex, age);
} while(0);
Py_UNBLOCK_THREADS;
Py_END_ALLOW_THREADS;
PyGILState_Release(gstate);
}
void Person::Show()
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //申请获取GIL
Py_BEGIN_ALLOW_THREADS;
Py_BLOCK_THREADS;
do
{
PyObject_CallMethod(m_pHandle, "show", NULL, NULL);
} while(0);
Py_UNBLOCK_THREADS;
Py_END_ALLOW_THREADS;
PyGILState_Release(gstate);
}
关于 PyInstance_New 的补充说明
如果 Python类的构造函数需要传入参数,则也可以通过 PyInstance_New 传参,参考示例如下:
PyObject *pArgs = PyTuple_New(4);
if (!pArgs)
{
printf(“PyTuple_New failed!\n”);
break;
}
PyTuple_SetItem(pArgs, 0, Py_BuildValue(“O”, PyObject类型的指针));
PyTuple_SetItem(pArgs, 1, Py_BuildValue(“s”, name));
PyTuple_SetItem(pArgs, 2, Py_BuildValue(“s”, sex));
PyTuple_SetItem(pArgs, 3, Py_BuildValue(“i”, age));
m_pHandle = PyInstance_New(pClass, pArgs, NULL);
C++多线程测试上述代码
multi_thread_sample.cpp
/***************************************
g++ main.cpp -o main -I/usr/include/python2.7/ -lpython2.7 -lpthread
****************************************/
#include "Person.hpp"
#include <time.h>
#include <pthread.h>
#define WAIT_COUNT 10
#define MAX_SIZE 20
Person *pAppBuf[MAX_SIZE] = {NULL};
pthread_t ThreadBuf[MAX_SIZE] = {0};
int nCurSize = 0;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
void *thread_func(void *args)
{
Person *pApp = (Person *)args;
int count = WAIT_COUNT;
while(count > 0)
{
count--;
//pthread_mutex_lock(&mut);
pApp->Push("jack", "man", count);
//pthread_mutex_unlock(&mut);
sleep(1);
}
pthread_exit(NULL);
}
void multi_thread_create(int n, Person *pPer)
{
int ret = 0;
if (n > MAX_SIZE)
{
return;
}
for (int i = 0; i < n; i++)
{
pthread_t threadid;
ret = pthread_create(&threadid, NULL, thread_func, pPer);
if (ret != 0)
{
LOG_DEBUG("pthread_create failed!\n");
break;
}
ThreadBuf[i] = threadid;
nCurSize++;
}
LOG_DEBUG("thread_create end\n");
}
void multi_thread_destory()
{
LOG_DEBUG("nCurSize = %d\n", nCurSize);
for (int i = 0; i < nCurSize; ++i)
{
LOG_DEBUG("pthread_join %d thread\n", i);
pthread_t threadid = ThreadBuf[i];
pthread_join(threadid, NULL);
}
}
int main()
{
int ret = 0;
Py_Initialize();
if (!Py_IsInitialized())
{
LOG_DEBUG("Py_Initialize error, return\n");
return -1;
}
PyEval_InitThreads();
int nInit = PyEval_ThreadsInitialized();
if (nInit)
{
LOG_DEBUG("PyEval_SaveThread\n");
PyEval_SaveThread();
}
Person *pPer = new Person();
multi_thread_create(5, pPer);
int count = WAIT_COUNT;
while (count > 0)
{
count--;
//pthread_mutex_lock(&mut);
pPer->Show();
printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
//pthread_mutex_unlock(&mut);
sleep(1);
}
multi_thread_destory();
delete pPer;
PyGILState_STATE gstate = PyGILState_Ensure();
Py_Finalize();
LOG_DEBUG("main end\n");
return 0;
}
参考文献
[1] 如何在C++中使用一个Python类
[2] Python/C API Reference Manual >> Abstract Objects Layer
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2019-01-30 双网卡单IP实现网卡冗余与负载均衡
2018-01-30 live555源码分析----RSTPServer创建过程分析