摘要:如果是這樣,就需要引入信號量進行控制。這應該是因為正在共享內存被上一次操作占用中還沒有釋放導致。
共享內存
共享內存的使用主要是為了能夠在同一臺機器不同的進程中共享一些數據,比如在多個 php-fpm 進程中共享當前進程的使用情況。這種通信也稱為進程間通信(Inter-Process Communication),簡稱 IPC。
PHP 內置的 shmop 擴展 (Shared Memory Operations) 提供了一系列共享內存操作的函數(可能是用的人不多吧,這一塊兒的文檔還沒有中文翻譯)。在 Linux 上,這些函數直接是通過調用 shm* 系列的函數實現,而 Winodows 上也通過對系統函數的封裝實現了同樣的調用。
主要函數:
shmop_close?— 關閉共享內存塊
shmop_delete?— 刪除共享內存塊
shmop_open?— 創建或打開共享內存塊
shmop_read?— 從共享內存塊中讀取數據
shmop_size?— 獲取共享內存塊的大小
shmop_write?— 向共享內存塊中寫入數據
與此相關的還有一個很重要的函數:ftok,通過文件的 inode 信息(*nix 上通過 stat 或 ls -i 命令查看)創建 IPC 的唯一 key(文件/文件夾的 inode 是唯一的)。這個函數在 Linux 上也是直接調用同名的系統函數實現,Windows 上還是使用一些封裝。
一個簡單的計數例子:
以上這段代碼沒執行一次計數加 1,而且數據是在不同進程之間共享的。也就是說除非手動刪除這塊內存使用,否則這個數據是不會重置的。
有個需要稍微注意的點:shmop_open 的第二個參數是個 flag,類似 fopen 的第二個參數,其取值有以前幾個:
"a" 只讀訪問;
"c" 如果內存片段不存在,則創建,如果存在,則可讀寫;
"w" 讀寫;
"n" 創建新的內存片段,如果同樣 key 的已存在,則會創建失敗,這是為了安全使用共享內存考慮。
此外,由于使用的共享內存片段是固定長度的,在存儲和讀取的時候要計算好數據的長度,不然可能會寫入失敗或者讀取空值。
信號控制既然上面使用到了共享內存存儲數據,就需要考慮是否有多個進程同時寫入數據到共享內存的情況,是否需要避免沖突。如果是這樣,就需要引入信號量進行控制。
PHP 也提供了類似的內置擴展 sysvsem(這個擴展在 Windows 環境下沒有,文檔中將 ftok 函數也歸到這個擴展中,但實際上 ftok 是在標準函數庫中提供的,所以在 Windows 下也是可用的)。
在說信號量控制之前,先說另外一件有意思的事情:看官方文檔你會發現這里同樣也有共享內存操作的函數(shm_*),因為這其實是同一類別(或者說來自于同一作者)的三個擴展,還有一個是 sysvmsg(隊列消息) 。函數的實現上稍有差別,但實際做的事情基本相同。這和上文的 shmop 擴展有什么區別呢?shmop 源碼下的 README 文件有簡單的說明:
PHP already had a shared memory extension (sysvshm) written by Christian Cartus
, unfortunately this extension was designed with PHP only in mind and offers high level features which are extremely bothersome for basic SHM we had in mind. 簡單說來:sysvshm 擴展提供的方法并不是原封不動的存儲用戶的數據,而是先使用 PHP 的變量序列化函數對參數進行序列化然后再進行存儲。這就導致通過這些方法存儲的數據無法和非 PHP 進程共享。不過這樣也能存儲更豐富的 PHP 數據類型,上文的擴展中 shmop_write 只能寫入字符串。那么為什么 sysvshm 同樣不支持 Windows 呢?因為其并沒有引入封裝了 shm* 系列函數的 tsrm_win32.h 的頭文件。
引入信號控制之后的示例:
但是本地想模擬實現寫入沖突實際上是非常難的(考慮到計算機的執行速度)。在本地測試中,使用 for 循環操作時如果不使用 shmop_close 關閉資源會出現無法打開共享內存的錯誤警告。這應該是因為正在共享內存被上一次操作占用中還沒有釋放導致。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30350.html
摘要:本人前一遍中提到,當進程數過多時,多進程插入數據庫表,超過了最大連接數,就會報錯,插入就會有失敗的情況。這樣就可以控制有的連接數不會達到上限,程序不會出現連接數據庫失敗的情況。多進程耗內存比較嚴重,下一步打算用多線程來試試。 本人前一遍blog中提到,當進程數過多時,多進程插入mysql數據庫表,超過了mysql最大連接數,就會報錯,插入就會有失敗的情況。想通過進程間通信來控制一下連接...
摘要:接受不到消息消息隊列通過指定而被創建后,任意一方銷毀了該隊列,都會導致其他發送或接收方失敗。用法場景進程,中代碼段要用到中代碼段的結果。完成了進程間同步問題此外進程間通信采用的方式是共享內存。 參考文章 深刻理解Linux進程間通信(IPC) 進程間通信(IPC)介紹 php高級應用之進程控制及進程間通訊 workman 作者發布 PHP 相關進程間通信擴展 -- System V ...
摘要:目的綜上所述,我的目標就是實現基于模式實現的多進程管理工具。備注下文中,父進程統稱為子進程統稱為。最后我們通過下圖來簡單的總結和描述這個多進程實現的過程控制上面實現了多進程和多進程的常駐內存,那如何去管理呢答案多進程通信。 _ | | _ __ __ _ _ __...
摘要:為了解決這個問題,我們必須引入互斥機制。實現互斥機制的最簡單辦法就是使用信號燈。信號量是另外一種進程間的方式,它同其他機構管道消息隊列不同。在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。 在單獨的一個PHP進程中讀寫、創建、刪除共享內存方面上你應該沒有問題了。但是實際運行中不可能只是一個PHP進程在運行中。如果在多個進程的情況下你還是沿用單個進程的...
閱讀 529·2023-04-25 14:26
閱讀 1285·2021-11-25 09:43
閱讀 3476·2021-09-22 15:25
閱讀 1447·2019-08-30 15:54
閱讀 520·2019-08-30 12:57
閱讀 765·2019-08-29 17:24
閱讀 3166·2019-08-28 18:13
閱讀 2672·2019-08-28 17:52