今天看了近一天關於多線程的應用中,如何安全調用python方面的資料,開始的時候看的簡直頭大如鬥,被python語言的全域鎖(Global Interpreter Lock)、線程狀態(Thread State )等都有點繞暈了,後來經過各方面文章和協助文檔的相互參考,發現對於2.4/2.5版本,提供了PyGILState_Ensure, PyGILState_Release,哎,這下可方便大發了。
一、首先定義一個封裝類,主要是保證PyGILState_Ensure, PyGILState_Release配對使用,而且這個類是可以嵌套使用的。
#include <python.h>
class PyThreadStateLock
{
public:
PyThreadStateLock(void)
{
state = PyGILState_Ensure( );
}
~PyThreadStateLock(void)
{
PyGILState_Release( state );
}
private:
PyGILState_STATE state;
};
二、在主線程中,這樣處理
// 初始化
Py_Initialize();
// 初始化線程支援
PyEval_InitThreads();
// 啟動子線程前執行,為了釋放PyEval_InitThreads獲得的全域鎖,否則子線程可能無法擷取到全域鎖。
PyEval_ReleaseThread(PyThreadState_Get());
// 其他的處理,如啟動子線程等
......
// 保證子線程調用都結束後
PyGILState_Ensure();
Py_Finalize();
// 之後不能再調用任何python的API
三、在主線程,或者子線程中,調用python本身函數的都採用如下處理
{
class PyThreadStateLock PyThreadLock;
// 調用python的API函數處理
......
}
呵呵,看這樣是否非常簡單了。
另外還有兩個和全域鎖有關的宏,Py_BEGIN_ALLOW_THREADS 和 Py_END_ALLOW_THREADS。這兩個宏是為了在較長時間的C函數調用前,臨時釋放全域鎖,完成後重新擷取全域鎖,以避免阻塞其他python的線程繼續運行。這兩個宏可以這樣調用
{
class PyThreadStateLock PyThreadLock;
// 調用python的API函數處理
......
Py_BEGIN_ALLOW_THREADS
// 調用需要長時間的C函數
......
Py_END_ALLOW_THREADS
// 調用python的API函數處理
......
}