Linux的多线程下使用c/c++调用Python方法示例

首先,所有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 
#include 
#include 

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;
}

编译过程:

g++ -I /usr/include/python2.7/ helloPython.cpp -o main  -lpython2.7 -lpthread -g

运行结果:

Linux的多线程下使用c/c++调用Python方法示例_第1张图片



你可能感兴趣的:(C-C++基础知识)