青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

   C++ 技術中心

   :: 首頁 :: 聯系 ::  :: 管理
  160 Posts :: 0 Stories :: 87 Comments :: 0 Trackbacks

公告

鄭重聲明:本BLOG所發表的原創文章,作者保留一切權利。必須經過作者本人同意后方可轉載,并注名作者(天空)和出處(CppBlog.com)。作者Email:coder@luckcoder.com

留言簿(27)

搜索

  •  

最新隨筆

最新評論

評論排行榜

腳本語言是快速編寫富有彈性的代碼的重要方法之一,在 Unix 系統自動化管理中已經應用了多種腳本語言。現在,在許多應用開發中,也提供了腳本層,這大大方便用戶實現通用任務自動處理或者編寫應用擴展,許多成功的應用,諸如 GIMPEmacsMS OfficePhotoShopAutoCAD 等都應用了腳本技術。在某種意義上,一切皆可腳本化。

在另一篇文章中,我們已經介紹了如何在 C 應用中嵌入 Python 語言,通過這項技術,可以讓應用的高級用戶來修改或定制化他們的程序,你可以充分利用 Python 的語言能力而不用自己去實現嵌入語言。Python 是一個不錯的的選擇,因為它提供了干凈直觀的 C 語言 API。關于如何在 C 應用中嵌入 Python 解釋器,你可以參考:Python成為嵌入式語言一文。

現在我們來更深入地探討一些問題。 鑒于許多復雜的應用都會利用多線程技術,本文將著重介紹如何創建線程安全的界面來調用Python解釋器。

這里的所有例子都是用 Python 2.7.2,所有的 Python 函數都以extern “C”定義,因此對于 C C++,其使用是別無二致的。
Python C 和線程

C程序中創建執行線程是很簡單的。在 Linux 中,通常的做法是使用 POSIX 線程(pthread) API 并調用 pthread_create 函數。關于如何使用 pthreads,你可以參考 Felix Garcia Javier Fernandez 著的 “POSIX Thread Libraries”一文。為了支持多線程, Python 使用了互斥使訪問內部數據結構串行化。這種互斥即全局解釋器鎖 – global interpreter lock”,當某個線程想使用 Python C API的時候,它必須獲得 全局解釋器鎖,這避免了會導致解析器狀態崩潰的競爭條件(race condition)

互斥的鎖定和釋放是通過 PyEval_AcquireLock Eval_ReleaseLock 來描述的。調用了 PyEval_AcquireLock 之后,可以安全地假定你的線程已經持有了鎖,其他相關線程不是被阻塞就是在執行與 Python 解析器無關的代碼。現在你可以任意調用 Python 函數了。一旦取得了鎖,你必須確保調用 PyEval_ReleaseLock 來釋放它,否則就會導致線程死鎖并凍結其他 Python 線程。

更復雜的情況是,每個運行 Python 的線程維護著自己的狀態信息。這些和特定線程相關的數據存儲在稱為 PyThreadState 的對象中。當在多線程應用中用 C 語言調用 Python API 函數時,你必須維護自己的 PyThreadState 對象以便能安全地執行并發的 Python 代碼。

如果你對開發多線程應用相當有經驗,你可能會發現全局解釋器鎖的概念相當不方便。不過,現在它已經不像首次出現時那樣糟糕了。當 Python 對腳本進行解釋時,它會定期切換出當前 PyThreadState 對象并釋放全局解釋器鎖,從而將控制權釋放給其他線程。之前被阻塞的線程可以試圖鎖定全局解釋器鎖從而被運行。有些時候,原來的線程會再次獲得全局解釋器鎖再次切回解釋器。

這意味著當調用 PyEval_SimpleString 時,即使你持有全局解釋器鎖,其他線程仍有機會被執行,這樣的副作用無可避免。另外,當你調用以 C 語言寫就的 Python 模塊(包括許多內置模塊) 存在著將控制權釋放給其他線程的可能性。基于這個原因,當你用兩個 C 線程來執行計算密集的 Python 腳本,它們確實能分享 CPU 時間并發運行,但由于全局解釋器鎖的存在,在多處理器的計算機上,Python 無法通過線程充分計算機的 CPU 處理能力。

啟用線程支持
在多線程的 C 程序使用 Python API 之前,必須調用一些初始化例程。如果編譯解釋器庫時啟用了多線程支持(通常情況如此),你就有了一個是否啟用線程的運行時選項。除非你計劃使用線程,否則不建議啟用該選項。未啟用該選項,Python 可以避免因互斥鎖定其內部數據結構而產生的系統開銷。但是如果你打算用 Python 來擴展多線程應用,你就需要在初始化解釋器的時候啟用線程支持。我個人建議,應該在主線程執行時就初始化 Python,最好是在應用程序啟動的時候,就調用下面兩行代碼:

// initialize Python
Py_Initialize();
// initialize thread support
PyEval_InitThreads();

這兩個函數都返回 void,所以無需檢查錯誤代碼。現在,我們可以假定 Python 解釋器已準備好執行 Python 代碼。Py_Initialize 分配解釋器庫使用的全局資源。調用PyEval_InitThreads 則啟用運行時線程支持。這導致 Python 啟用其內部的互斥鎖機制,用于解釋器內代碼關鍵部分的系列化訪問。此函數的另一個作用是鎖定全局解釋器鎖。該函數完成后,需要由用戶負責釋放該鎖。不過,在釋放鎖之前, 你應該捕獲當前 PyThreadState 對象的指針。后續創建新的 Python 線程以及結束使用 Python 時要正確關閉解釋器,都需要用到該對象。下面這段代碼用來捕獲 PyThreadState 對象指針:

PyThreadState * mainThreadState = NULL;
// save a pointer to the main PyThreadState object
mainThreadState = PyThreadState_Get();
// release the lock
PyEval_ReleaseLock();


創建新的執行線程

Python 里,每個執行 Python 代碼的線程都需要一個 PyThreadState 對象。解釋器使用此對象來管理每個線程獨立的數據空間。理論上,這意味著一個線程中的動作不會牽涉到另一個線程的狀態。例如,你在一個線程中拋出異常,其他 Python 代碼片段仍會繼續運行,就好象什么事情都沒有發生一樣。你必須幫助 Python 管理每個線程的數據。為此,你需要為每個執行 Python 代碼的 C 線程手工創建一個 PyThreadState 對象.要創建 PyThreadState 對象,你需要用到既有的 PyInterpreterState 對象。PyInterpreterState 對象帶有為所有參與的線程所共享的信息。當你初始化 Python 時,它就會創建一個 PyInterpreterState 對象,并將它附加在主線程的 PyThreadState 對象上。你可以使用該解釋器對象為你自己的 C 現成創建新的 PyThreadState。請參考下面代碼

// get the global lock
PyEval_AcquireLock();
// get a reference to the PyInterpreterState
PyInterpreterState * mainInterpreterState = mainThreadState->interp;
// create a thread state object for this thread
PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
// free the lock
PyEval_ReleaseLock();
執行 Python 代碼
現在我們已創建 PyThreadState 對象,你的 C 線程就可以開始使用 Python API 執行 Python 腳本。從 C 線程執行 Python 代碼時,你必須遵守一些簡單的規則。首先,您在進行任何會改變當前線程狀態的操作前必須持有全局解釋器鎖。第二,必須在執行任何 Python 代碼之前,必須將該線程特定的 PyThreadState 對象加載到解釋器。一旦您已經滿足這些條件,您可以通過諸如 PyEval_SimpleString 函數來執行任意的 Python 代碼,并記得在執行結束時切出 PyThreadState 對象并釋放全局解釋器鎖。請參考下面代碼,注意代碼中鎖定、 切換、 執行、 切換,解鎖的對稱關系:
// grab the global interpreter lock
PyEval_AcquireLock();
// swap in my thread state
PyThreadState_Swap(myThreadState);
// execute some python code
PyEval_SimpleString("import sys\n");
PyEval_SimpleString(
"sys.stdout.write(‘Hello from a C thread!\n‘)\n");
// clear the thread state
PyThreadState_Swap(NULL);
// release our hold on the global interpreter
PyEval_ReleaseLock();


清除線程
一旦你的 C 線程不再需要 Python 解釋器,你必須釋放相關資源。為此,需要刪除該線程的 PyThreadState 對象,相關代碼如下:

// grab the lock
PyEval_AcquireLock();
// swap my thread state out of the interpreter
PyThreadState_Swap(NULL);
// clear out any cruft from thread state object
PyThreadState_Clear(myThreadState);
// delete my thread state object
PyThreadState_Delete(myThreadState);
// release the lock
PyEval_ReleaseLock();

通過使用 Python API ,這個線程很有效率地完成了上述工作。現在你可以安全地調用 pthread_ext 來結束該線程的運行。
關閉解釋器
一旦應用不在需要 Python 解釋器,你可以用下面的代碼將 Python 關閉掉:

// shut down the interpreter
PyEval_AcquireLock();
Py_Finalize();

注意:因為 Python 已經被關系,這里就不需要釋放鎖。請確保在調用 Py_Finalize 之前用 PyThreadState_Clear PyThreadState_Delete 刪除掉所有線程狀態對象。

小結:
作為嵌入式語言,Python 是一個不錯的選擇。Python 解釋器同時支持嵌入和擴展,它允許 C 應用程序代碼和嵌入的 Python 腳本之間的雙向通信。此外,多線程支持促進了與多線程應用程序的集成,而且不影響性能。

你可以從本文的后面下載有關案例Python embedded HTTP Server (29),該案例實現了一個內嵌 Python 解釋器的多線程 HTTP 服務器。此外我推薦您去 http://www.python.org/docs/api/ 閱讀有關的 Python C API 文檔。另外 Python 解釋器本身的代碼也是一個很有價值的參考。

 

posted on 2013-12-06 10:34 C++技術中心 閱讀(9582) 評論(2)  編輯 收藏 引用 所屬分類: 其他編程

Feedback

# re: c++多線程調用python 2013-12-06 17:26 佛山華康醫院
http://blog.sina.com.cn/s/blog_473fa3520100q50o.html  回復  更多評論
  

# re: c++多線程調用python 2014-06-29 09:17 111111
每個線程在執行時都得鎖定GIL,還不影響性能?  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲色诱最新| 亚洲国产裸拍裸体视频在线观看乱了| 一本久道久久综合狠狠爱| 久久国产一二区| 亚洲午夜精品在线| 欧美日韩性生活视频| 亚洲黄色性网站| 免费久久精品视频| 久久久久久久久久久久久久一区| 国产欧美1区2区3区| 中文一区二区在线观看| 亚洲人成人77777线观看| 快射av在线播放一区| 在线精品亚洲一区二区| 蜜臀va亚洲va欧美va天堂| 亚洲国产精选| 亚洲午夜激情网站| 日韩午夜精品视频| 欧美色中文字幕| 亚洲尤物精选| 亚洲亚洲精品三区日韩精品在线视频| 欧美日本在线| 亚洲免费在线播放| 欧美一区二区三区免费在线看 | 国产日产欧产精品推荐色| 羞羞答答国产精品www一本| 亚洲无线一线二线三线区别av| 欧美午夜理伦三级在线观看| 亚洲综合视频1区| 午夜精品久久久久久99热软件| 国产日韩欧美视频| 欧美韩国日本一区| 欧美日韩综合视频| 欧美在线免费看| 久久午夜影视| 99这里有精品| 午夜精品久久久久久久99樱桃| 国内精品伊人久久久久av一坑| 欧美高清在线视频| 欧美视频免费看| 久久久中精品2020中文| 欧美成人精品在线| 欧美一区二区啪啪| 免费成人美女女| 亚洲一区影音先锋| 欧美在线免费观看亚洲| 亚洲人精品午夜在线观看| 在线视频中文亚洲| 亚洲第一综合天堂另类专| 亚洲色无码播放| 亚洲高清不卡一区| 亚洲综合国产| 亚洲精品在线观看免费| 香蕉久久一区二区不卡无毒影院| 亚洲国产毛片完整版| 亚洲一区在线免费观看| 亚洲日本免费| 久久黄色级2电影| 亚洲一区二区三区在线| 美日韩精品视频免费看| 欧美在线免费| 欧美色中文字幕| 亚洲人被黑人高潮完整版| 激情综合自拍| 午夜视频一区| 亚洲综合色婷婷| 欧美日韩国产不卡| 欧美韩日精品| 一区二区三区在线观看国产| 亚洲自拍高清| 亚洲一区二区三区高清不卡| 欧美大胆人体视频| 欧美大片免费观看| 国产一区在线看| 亚洲亚洲精品在线观看 | 国产精品久在线观看| 在线看日韩av| 欧美一区二区三区在线视频| 亚洲一二三区在线| 欧美激情一级片一区二区| 久久欧美肥婆一二区| 国产精品一区二区在线| 一区二区激情视频| 中文日韩电影网站| 欧美日韩色综合| 亚洲美女区一区| 日韩视频一区二区| 欧美顶级大胆免费视频| 欧美韩国一区| 亚洲精品久久久一区二区三区| 久久久www成人免费无遮挡大片| 久久成人国产精品| 国产欧美日韩视频一区二区| 亚洲一二三区在线观看| 午夜精品一区二区三区电影天堂| 欧美三级免费| 亚洲在线播放电影| 欧美亚洲免费在线| 国产一区二区三区在线观看视频| 午夜精品福利视频| 久久免费国产| 亚洲福利国产精品| 欧美黄色小视频| 99在线精品免费视频九九视| 亚洲欧美日韩国产精品| 国产精品美腿一区在线看| 亚洲一区在线观看免费观看电影高清| 午夜欧美不卡精品aaaaa| 国产毛片精品视频| 久久精品一本| 欧美国产大片| 亚洲视频你懂的| 国产无一区二区| 久久久久久夜| 亚洲精品欧美激情| 欧美与欧洲交xxxx免费观看| 国产综合久久| 欧美极品色图| 亚洲欧美日韩网| 欧美激情中文字幕一区二区| 99成人在线| 国产手机视频一区二区| 久热精品视频在线免费观看 | 欧美国产视频一区二区| 亚洲视频在线看| 久久综合狠狠综合久久激情| 亚洲免费久久| 国产一级久久| 欧美人成网站| 久久爱www久久做| 亚洲区在线播放| 久久精品国产一区二区三| 亚洲欧洲另类国产综合| 国产精品亚洲综合久久| 麻豆国产精品777777在线| 99精品欧美一区二区三区综合在线| 久久国产精品久久w女人spa| 99精品欧美一区二区蜜桃免费| 国产亚洲欧美日韩日本| 欧美在线视频a| 一本色道久久88亚洲综合88| 蘑菇福利视频一区播放| 午夜精品久久久久久久| 亚洲精品日产精品乱码不卡| 国产精品女主播| 在线播放不卡| 久久精品国产免费看久久精品| 亚洲国产另类久久精品| 国产亚洲精品综合一区91| 欧美啪啪一区| 久久亚洲欧美| 欧美一区在线看| 亚洲午夜一级| 日韩亚洲欧美精品| 亚洲国产欧美在线| 老色鬼久久亚洲一区二区| 先锋影音久久久| 亚洲一区免费网站| 一区二区三区成人| 亚洲精品系列| 亚洲精品免费网站| 亚洲国产精品99久久久久久久久| 国产亚洲欧美日韩精品| 国产精品伊人日日| 国产精品久久久久aaaa樱花| 欧美日韩国产电影| 欧美另类高清视频在线| 欧美www视频在线观看| 久久亚洲一区二区| 久久在线视频在线| 久久久久国色av免费看影院| 欧美一区二区三区四区高清| 午夜宅男欧美| 久久国产欧美| 久久婷婷人人澡人人喊人人爽| 欧美一区高清| 久久激情一区| 久久久久久网址| 蜜桃精品久久久久久久免费影院| 猫咪成人在线观看| 欧美成人蜜桃| 欧美剧在线观看| 欧美日韩在线综合| 国产精品热久久久久夜色精品三区| 国产精品色午夜在线观看| 国产精品一区久久| 黄色成人免费网站| 亚洲国产精品va在线观看黑人| 亚洲高清不卡在线观看| 亚洲精品乱码久久久久久日本蜜臀 | 亚洲高清不卡| 亚洲精品乱码久久久久久蜜桃91 | 亚洲欧美日韩中文播放| 午夜在线不卡| 久久亚洲一区| 亚洲国产精品欧美一二99| 一本不卡影院| 香蕉乱码成人久久天堂爱免费| 久久福利电影| 欧美精品在线一区二区三区|