【Python笔记1.3】C/C++多线程调用Python函数

概述

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值