国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - PHP教程 - PHP及Zend Engine的線程安全模型分析

PHP及Zend Engine的線程安全模型分析

2019-12-17 14:20PHP教程網 PHP教程

在閱讀PHP源碼和學習PHP擴展開發的過程中,我接觸到大量含有“TSRM”字眼的宏。通過查閱資料,知道這些宏與Zend的線程安全機制有關,而絕大多數資料中都建議按照既定規則使用這些宏就可以,而沒有說明這些宏的具體作用

不知道怎么回事總是令人不舒服的,因此我通過閱讀源碼和查閱有限的資料簡要了解一下相關機制,本文是我對研究內容的總結。 本文首先解釋了線程安全的概念及PHP中線程安全的背景,然后詳細研究了PHP的線程安全機制ZTS(Zend Thread Safety)及具體的實現TSRM,研究內容包括相關數據結構、實現細節及運行機制,最后研究了Zend對于單線程和多線程環境的選擇性編譯問題。 

線程安全 
線程安全問題,一言以蔽之就是多線程環境下如何安全存取公共資源。我們知道,每個線程只擁有一個私有棧,共享所屬進程的堆。在C中,當一個變量被聲明在任何函數之外時,就成為一個全局變量,這時這個變量會被分配到進程的共享存儲空間,不同線程都引用同一個地址空間,因此一個線程如果修改了這個變量,就會影響到全部線程。這看似為線程共享數據提供了便利,但是PHP往往是每個線程處理一個請求,因此希望每個線程擁有一個全局變量的副本,而不希望請求間相互干擾。 早期的PHP往往用于單線程環境,每個進程只啟動一個線程,因此不存在線程安全問題。后來出現了多線程環境下使用PHP的場景,因此Zend引入了Zend線程安全機制(Zend Thread Safety,簡稱ZTS)用于保證線程的安全。 

ZTS的基本原理及實現 
基本思想 
說起來ZTS的基本思想是很直觀的,不是就是需要每個全局變量在每個線程都擁有一個副本嗎?那我就提供這樣的機制: 在多線程環境下,申請全局變量不再是簡單聲明一個變量,而是整個進程在堆上分配一塊內存空間用作“線程全局變量池”,在進程啟動時初始化這個內存池,每當有線程需要申請全局變量時,通過相應方法調用TSRM(Thread Safe Resource Manager,ZTS的具體實現)并傳遞必要的參數(如變量大小等等),TSRM負責在內存池中分配相應內存區塊并將這塊內存的引用標識返回,這樣下次這個線程需要讀寫此變量時,就可以通過將唯一的引用標識傳遞給TSRM,TSRM將負責真正的讀寫操作。這樣就實現了線程安全的全局變量。下圖給出了ZTS原理的示意圖: 

 

Thread1和Thread2同屬一個進程,其中各自需要一個全局變量Global Var,TSRM為兩者在線程全局內存池中(黃色部分)各自分配了一個區域,并且通過唯一的ID進行標識,這樣兩個線程就可以通過TSRM存取自己的變量而互不干擾。 下面通過具體的代碼片段看一下Zend具體是如何實現這個機制的。這里我用的是PHP5.3.8的源碼。 TSRM的實現代碼在PHP源碼的“TSRM”目錄下。 

數據結構 
TSRM中比較重要的數據結構有兩個:tsrm_tls_entry和tsrm_resource_type。下面先看tsrm_tls_entry。 tsrm_tls_entry定義在TSRM/TSRM.c中: 

復制代碼代碼如下:


typedef struct _tsrm_tls_entry tsrm_tls_entry; 

struct _tsrm_tls_entry { 
void **storage; 
int count; 
THREAD_T thread_id; 
tsrm_tls_entry *next; 


每個tsrm_tls_entry結構負責表示一個線程的所有全局變量資源,其中thread_id存儲線程ID,count記錄全局變量數,next指向下一個節點。storage可以看做指針數組,其中每個元素是一個指向本節點代表線程的一個全局變量。最終各個線程的tsrm_tls_entry被組成一個鏈表結構,并將鏈表頭指針賦值給一個全局靜態變量tsrm_tls_table。注意,因為tsrm_tls_table是一個貨真價實的全局變量,所以所有線程會共享這個變量,這就實現了線程間的內存管理一致性。tsrm_tls_entry和tsrm_tls_table結構的示意圖如下: 

 

tsrm_resource_type的內部結構相對簡單一些: 

復制代碼代碼如下:


typedef struct { 
size_t size; 
ts_allocate_ctor ctor; 
ts_allocate_dtor dtor; 
int done; 


tsrm_resource_type;上文說過tsrm_tls_entry是以線程為單位的(每個線程一個節點),而tsrm_resource_type以資源(或者說全局變量)為單位,每次一個新的資源被分配時,就會創建一個tsrm_resource_type。所有tsrm_resource_type以數組(線性表)的方式組成tsrm_resource_table,其下標就是這個資源的ID。每個tsrm_resource_type存儲了此資源的大小和構造、析構方法指針。某種程度上,tsrm_resource_table可以看做是一個哈希表,key是資源ID,value是tsrm_resource_type結構。 

實現細節 
這一小節分析TSRM一些算法的實現細節。因為整個TSRM涉及代碼比較多,這里揀其中具有代表性的兩個函數分析。 第一個值得注意的是tsrm_startup函數,這個函數在進程起始階段被sapi調用,用于初始化TSRM的環境。由于tsrm_startup略長,這里摘錄出我認為應該注意的地方: 

復制代碼代碼如下:


/* Startup TSRM (call once for the entire process) */ 
TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename) 

/* code... */ 

tsrm_tls_table_size = expected_threads; 

tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *)); 
if (!tsrm_tls_table) { 
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table")); 
return 0; 

id_count=0; 

resource_types_table_size = expected_resources; 
resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type)); 
if (!resource_types_table) { 
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table")); 
free(tsrm_tls_table); 
tsrm_tls_table = NULL; 
return 0; 


/* code... */ 

return 1; 


其實tsrm_startup的主要任務就是初始化上文提到的兩個數據結構。第一個比較有意思的是它的前兩個參數:expected_threads和expected_resources。這兩個參數由sapi傳入,表示預計的線程數和資源數,可以看到tsrm_startup會按照這兩個參數預先分配空間(通過calloc)。因此TSRM會首先分配可容納expected_threads個線程和expected_resources個資源的。要看各個sapi默認會傳入什么,可以看各個sapi的源碼(在sapi目錄下),我簡單看了一下: 

 

可以看到比較常用的sapi如mod_php5、php-fpm和cgi都是預分配一個線程和一個資源,這樣是因為不愿浪費內存空間,而且多數情況下PHP還是運行于單線程環境。 這里還可以看到一個id_count變量,這個變量是一個全局靜態變量,其作用就是通過自增產生資源ID,這個變量在這里被初始化為0。所以TSRM產生資源ID的方式非常簡單:就是一個整形變量的自增。 第二個需要仔細分析的就是ts_allocate_id,編寫過PHP擴展的朋友對這個函數肯定不陌生,這個函數...

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 91麻豆精品国产91久久久更新资源速度超快 | 夜夜久久| 国产成人一区二区三区 | 可以免费看黄色的网站 | 久久久久久亚洲一区二区三区蜜臀 | 在线免费黄色 | 性视屏| 欧美电影免费网站 | 久久99精品国产麻豆婷婷 | 在线精品国产一区二区三区 | 高清久久 | 午夜视频在线免费看 | 中文字幕色 | 免费裸体无遮挡黄网站免费看 | 欧美成人影院 | 三级黄色片在线免费观看 | 成人片免费看 | 一区福利 | 国产一级纯肉体一级毛片 | 国产视频精品免费 | 久久综合久色欧美综合狠狠 | 欧美日韩亚洲二区 | 犬夜叉在线观看 | 亚洲一区在线免费观看 | 国产在线视频网站 | 日韩超级大片免费看国产国产播放器 | 国产在线精品一区二区三区 | 中国黄色视屏 | 亚洲激情视频 | 久久99精品国产麻豆婷婷洗澡 | 中文字幕国产一区 | 99re国产 | 亚洲+变态+欧美+另类+精品 | av在线免费观看网站 | 日韩一区二区三区精品 | 亚洲精品视频网站在线观看 | 国产黄色美女 | 最近中文字幕免费观看 | 91免费在线 | 亚洲国产精品成人 | 手机看片在线 |