摘要:中專門為解決線程安全的問題抽象出了一個線程安全資源管理器,實(shí)現(xiàn)原理比較簡單既然共用資源這么困難那么就干脆不共用,各線程不再共享同一份全局變量,而是各復(fù)制一份,使用數(shù)據(jù)時各線程各取自己的副本,互不干擾。
1.線程安全資源管理器
PHP的SAPI多數(shù)是單線程環(huán)境,比如cli、fpm、cgi,每個進(jìn)程只啟動一個主線程,這種模式下是不存在線程安全問題的,但是也有多線程的環(huán)境,比如Apache,這種情況下就需要考慮線程安全的問題了,因為PHP中有很多全局變量,比如最常見的:EG、CG,如果多個線程共享同一個變量將會沖突,所以PHP為多線程的應(yīng)用模型提供了一個安全機(jī)制:Zend線程安全(Zend Thread Safe, ZTS)。
PHP中專門為解決線程安全的問題抽象出了一個線程安全資源管理器(Thread Safe Resource Mananger, TSRM),實(shí)現(xiàn)原理比較簡單:既然共用資源這么困難那么就干脆不共用,各線程不再共享同一份全局變量,而是各復(fù)制一份,使用數(shù)據(jù)時各線程各取自己的副本,互不干擾。
typedef struct { size_t size; //資源的大小 ts_allocate_ctor ctor; //初始化函數(shù) ts_allocate_dtor dtor; int done; } tsrm_resource_type; struct _tsrm_tls_entry { void **storage; //資源數(shù)組 int count; //擁有的資源數(shù):storage數(shù)組大小 THREAD_T thread_id; //所屬線程id tsrm_tls_entry *next; };
如果一個資源會被多線程使用,那么首先需要預(yù)先向TSRM注冊資源,然后TSRM為這個資源分配一個唯一的編號,并把這種資源的大小、初始化函數(shù)等保存到一個tsrm_resource_type結(jié)構(gòu)中,各線程只能通過TSRM分配的那個編號訪問這個資源;然后當(dāng)線程拿著這個編號獲取資源時TSRM如果發(fā)現(xiàn)是第一次請求,則會根據(jù)注冊時的資源大小分配一塊內(nèi)存,然后調(diào)用初始化函數(shù)進(jìn)行初始化,并把這塊資源保存下來供這個線程后續(xù)使用。
每個線程擁有一個tsrm_tls_entry結(jié)構(gòu),當(dāng)前線程的所有資源保存在storage數(shù)組中,下標(biāo)就是各資源的id。另外所有線程的tsrm_tls_entry結(jié)構(gòu)通過一個數(shù)組保存:tsrm_tls_table,這是個全局變量,每個線程的tsrm_tls_entry結(jié)構(gòu)在這個數(shù)組中的位置是根據(jù)線程id與預(yù)設(shè)置的線程數(shù)(tsrm_tls_table_size)取模得到的,也就是說有可能多個線程保存在tsrm_tls_table同一位置,所以tsrm_tls_entry是個鏈表,查找資源時首先根據(jù):線程id % tsrm_tls_table_size得到一個tsrm_tls_entry,然后開始遍歷鏈表比較thread_id確定是否是當(dāng)前線程的。線程本地存儲(Thread Local Storage, TLS),在創(chuàng)建完當(dāng)前線程的tsrm_tls_entry后會把這個值保存到當(dāng)前線程的TLS中,這樣在ts_resource()獲取資源時中就可以通過tsrm_tls_get()直接取到了,節(jié)省加鎖檢索的時間。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/28582.html
摘要:但在多線程模式下會有多個,也就是說每個線程都有一個獨(dú)立的內(nèi)存池內(nèi)存分配分配超過內(nèi)存的申請,與通用的內(nèi)存申請沒有太大差別,只是將申請的內(nèi)存塊通過單鏈表進(jìn)行了管理。的分配實(shí)際就是分配多個,的分配也是內(nèi)存分配的基礎(chǔ),它是向系統(tǒng)申請內(nèi)存的唯一粒度。 1.Zend內(nèi)存池 內(nèi)存池是內(nèi)核中最底層的內(nèi)存操作,定義了三種粒度的內(nèi)存塊:chunk、page、slot,每個chunk的大小為2M,page大...
摘要:插入一個元素時先將元素按先后順序插入數(shù)組,位置是,再根據(jù)的哈希值映射到散列表中的某個位置,將存入這個位置查找時先在散列表中映射到,得到在數(shù)組的位置,再從數(shù)組中取出元素。目前只有兩種類型會使用這種機(jī)制。 1.變量結(jié)構(gòu) typedef struct _zval_struct zval; typedef union _zend_value { zend_long ...
摘要:局部變量中局部變量分配在結(jié)構(gòu)上,每次執(zhí)行都會生成一個新的,局部變量在執(zhí)行之初分配,然后在執(zhí)行結(jié)束時釋放,這是局部變量的生命周期。 1.局部變量 PHP中局部變量分配在zend_execute_data結(jié)構(gòu)上,每次執(zhí)行zend_op_array都會生成一個新的zend_execute_data,局部變量在執(zhí)行之初分配,然后在執(zhí)行結(jié)束時釋放,這是局部變量的生命周期。 讀寫操作:局部變量通過...
摘要:代碼的編譯的解析過程任務(wù)就是將代碼轉(zhuǎn)化為數(shù)組,代碼里的所有信息都保存在數(shù)組中,然后將數(shù)組交給引擎執(zhí)行,就是內(nèi)核具體執(zhí)行的命令,比如賦值加減操作函數(shù)調(diào)用等,每一條都對應(yīng)一個處理,這些是提前定義好的函數(shù)。 1.PHP代碼的編譯 PHP的解析過程任務(wù)就是將PHP代碼轉(zhuǎn)化為opcode數(shù)組,代碼里的所有信息都保存在opcode數(shù)組中,然后將opcode數(shù)組交給zend引擎執(zhí)行,opcode就是...
閱讀 1176·2021-11-23 10:10
閱讀 1499·2021-09-30 09:47
閱讀 887·2021-09-27 14:02
閱讀 2967·2019-08-30 15:45
閱讀 3020·2019-08-30 14:11
閱讀 3610·2019-08-29 14:05
閱讀 1820·2019-08-29 13:51
閱讀 2206·2019-08-29 11:33