DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

概述

  在上一篇笔记中讲述了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】

 
posted on   DoubleLi  阅读(123)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2019-01-30 双网卡单IP实现网卡冗余与负载均衡
2018-01-30 live555源码分析----RSTPServer创建过程分析
点击右上角即可分享
微信分享提示