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