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

首先,所有python的函数都是用extern "C"定义的,因此对于C和C++,其使用是一样的。

c语言调用python必须要有的API(不管有没有多线程):

 
 
PyRun_SimpleString //执行一段python代码
 
PyImport_Import //导入python模块
 
PyModule_GetDict//因为python一个模块就是一个命名空间,命名空间由dict对象实现的
 
PyDict_GetItemString
 
PyTuple_New//创建一个元组,c语言和python之间通过元组传参
 
Py_BuildValue
 
PyTuple_SetItem
 
PyObject_Call//调用python函数对象
 
 

python类型xx转为C语言的类型yy:   用PyxxAsyy函数

C类型YY转为python的XX类型要用:PyXXFromYY函数

C语言调用python之前要初始化,用完之后要销毁:

 
 
Py_Initialize(); //初始化
 
 
 
do_something.....
 
 
 
Py_Finalize(); //销毁,此后不能再调用有关python的API
 
 

众所周知,python有一个臭名昭著的GIL全局解释锁,拿到这个锁的线程才能执行python程序。所以在用C语言的多线程调用python之前,还需要调用下面的函数:

 
 
PyEval_InitThreads();
 
以下两个函数的效果相当,用于释放GIL锁
 
// PyEval_ReleaseThread(PyThreadState_Get());
 
// PyEval_ReleaseLock();
 
 
 
do_something().....
 
 
 
PyGILState_Ensure();
 
 

调用PyEval_InitThreads()函数的线程(一般是主线程),也就拿到了这个GIL锁,必须主动地释放这个锁,以便它创建的线性能够拿到这把锁。所以上边的代码加上了两行注释。

在子线程函数中,必须主动去获得这个GIL, 用完之后进行释放,最好的方法是定义一个类。用完之后自动析构。

 
 
class PyThreadStateLock
 
{
 
public:
 
PyThreadStateLock()
 
{
 
state = PyGILState_Ensure(); //获得锁
 
}
 
~PyThreadStateLock()
 
{
 
PyGILState_Release(state); //释放锁
 
}
 
private:
 
PyGILState_STATE state;
 
 
 
};
 
 

我写了一个python程序,接受一个int型变量的参数,然后打印它。命名为mypy.py

 
 
#_*_ coding:utf-8 _*_
 
#!/usr/bin/python2.7
 
 
 
def my_pFun(a):
 
print "a = :" + str(a)
 
 
然后是c++程序,主线程创建三个线程,分别调用这个python 程序。命名为helloPython.cpp

 
 
#include <Python.h>
 
#include <pthread.h>
 
#include <iostream>
 
 
 
using namespace std;
 
 
 
class PyThreadStateLock
 
{
 
public:
 
PyThreadStateLock()
 
{
 
state = PyGILState_Ensure();
 
}
 
~PyThreadStateLock()
 
{
 
PyGILState_Release(state);
 
}
 
private:
 
PyGILState_STATE state;
 
 
 
};
 
 
 
PyObject* pFunc = NULL;//全局可调用的python程序中的函数
 
void pFunc_init()
 
{
 
 
 
PyRun_SimpleString("import sys");
 
PyRun_SimpleString("sys.path.append('./')");
 
 
 
PyObject* pyModule = PyImport_Import(PyString_FromString("mypy"));
 
if(pyModule == NULL)
 
{
 
printf("load mypy failed\n");
 
exit(0);
 
}
 
PyObject* pDict = PyModule_GetDict(pyModule);
 
pFunc = PyDict_GetItemString(pDict, "my_pFun");
 
}
 
 
 
void * threadFunc(void* arg)
 
{
 
//PyEval_ReleaseLock();
 
pthread_detach(pthread_self());
 
PyObject* pkwargs = NULL;
 
PyThreadStateLock PyThreadLock;
 
int a = *(int*)arg;
 
delete (int*)arg;
 
 
 
cout << "in thread:" << pthread_self() << " ****" << a << endl;
 
PyObject* pArgs = PyTuple_New(1);
 
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", a));
 
PyObject_Call(pFunc, pArgs, pkwargs);
 
cout << "sleep" << endl;
 
sleep(3);
 
//exit(0);//如果使用这个函数,直接退出该进程
 
//pthread_exit(NULL);
 
 
 
}
 
 
 
 
 
int main(int argc, char *argv[])
 
{
 
Py_Initialize();
 
PyEval_InitThreads();
 
pFunc_init();
 
 
 
pthread_t tid[3];
 
PyEval_ReleaseThread(PyThreadState_Get());
 
for(int i = 0; i < 3; i++)
 
{
 
int* j = new int(i); //这里不能传&i进去,否则所有的线程获得同一个地址
 
pthread_create(&tid[i], NULL, threadFunc, j);
 
}
 
 
 
 
 
for(int i = 0; i < 3; i++)
 
{
 
pthread_join(tid[i], NULL);//使用了pthread_detach还是要join,或者sleep也可以
 
}
 
 
 
PyGILState_Ensure();
 
Py_Finalize();
 
return 0;
 
}
 
 

编译过程:

<span style="font-size:16px;">g++ -I /usr/include/python2.7/ helloPython.cpp -o main  -lpython2.7 -lpthread -g</span>

运行结果:



 
posted on   DoubleLi  阅读(315)  评论(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创建过程分析
点击右上角即可分享
微信分享提示