【Python笔记1.2】C/C++多线程调用Python类

概述

在多线程开发中,往往会涉及很多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

猜你喜欢

转载自blog.csdn.net/u011362297/article/details/80997669