概述
在上一篇笔记中讲述了C/C++多线程调用Python类,但是如果Python提供的接口不是class封装的情况该怎么办呢,此时如何保证在C/C++多线程调用Python代码时能够正常运行呢?
在多线程开发中,尽量避免使用全局变量,我们可以将Python中需要全局初始化的变量放到一个字典(或元祖或列表)中,并将该字典作为handle整体返回给调用者。
python代码示例
class Person:
def __init__(self):
self.info = []
def push(self, name, sex, age):
self.info.append((name, sex, age))
# 下面是提供给调用者的接口
def init():
person = Person()
return person # 可以将其理解为 handle
def push(handle, name, sex, age):
handle.push(name, sex, age)
def show(handle):
print(handle.info)
调用上述Python的C++代码
Person.hpp 同【Python笔记1.2】
Person.cpp
#include "Person.hpp"
Person::Person()
{
PyObject* pFile = NULL;
PyObject* pModule = NULL;
PyObject* pFunc = 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;
}
pFunc = PyDict_GetItemString(m_pDict, "init");
if (!pFunc || !PyCallable_Check(pFunc))
{
printf("PyDict_GetItemString init failed!\n");
break;
}
m_pHandle = PyObject_CallObject(pFunc, NULL);
if (!m_pHandle)
{
printf("PyObject_CallObject init failed!\n");
break;
}
} while (0);
//if (pFunc)
// Py_DECREF(pFunc);
//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)
{
PyObject* pFunc = NULL;
PyObject* pArgs = NULL;
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //申请获取GIL
Py_BEGIN_ALLOW_THREADS;
Py_BLOCK_THREADS;
do
{
pFunc = PyDict_GetItemString(m_pDict, "push");
if (!pFunc || !PyCallable_Check(pFunc))
{
printf("PyDict_GetItemString push failed!\n");
break;
}
pArgs = PyTuple_New(4);
if (!pArgs)
{
printf("PyTuple_New failed!\n");
break;
}
PyTuple_SetItem(pArgs, 0, Py_BuildValue("O", m_pHandle));
PyTuple_SetItem(pArgs, 1, Py_BuildValue("s", name));
PyTuple_SetItem(pArgs, 2, Py_BuildValue("s", sex));
PyTuple_SetItem(pArgs, 3, Py_BuildValue("i", age));
PyObject_CallObject(pFunc, pArgs);
} while(0);
if (pArgs)
Py_DECREF(pArgs);
Py_UNBLOCK_THREADS;
Py_END_ALLOW_THREADS;
PyGILState_Release(gstate);
}
void Person::Show()
{
PyObject* pFunc = NULL;
PyObject* pArgs = NULL;
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //申请获取GIL
Py_BEGIN_ALLOW_THREADS;
Py_BLOCK_THREADS;
do
{
pFunc = PyDict_GetItemString(m_pDict, "show");
if (!pFunc || !PyCallable_Check(pFunc))
{
printf("PyDict_GetItemString show failed!\n");
break;
}
pArgs = PyTuple_New(1);
if (!pArgs)
{
printf("PyTuple_New failed!\n");
break;
}
PyTuple_SetItem(pArgs, 0, Py_BuildValue("O", m_pHandle));
PyObject_CallObject(pFunc, pArgs);
} while(0);
if (pArgs)
Py_DECREF(pArgs);
Py_UNBLOCK_THREADS;
Py_END_ALLOW_THREADS;
PyGILState_Release(gstate);
}
C++多线程测试上述代码
multi_thread_sample.cpp 同【Python笔记1.2】
参考文献
同 【Python笔记1.2】
分类:
python
【推荐】国内首个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创建过程分析