首先,所有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
运行结果: