首頁  >  文章  >  後端開發  >  php共享記憶體使用的程式碼詳細介紹

php共享記憶體使用的程式碼詳細介紹

黄舟
黄舟原創
2017-03-08 10:14:511395瀏覽

本文將討論在PHP4環境下如何使用進程間通訊機制-IPC(Inter-Process-Communication)。本文討論的軟體環境是linux+php4.0.4或更高版本。首先,我們假設你已經裝好了PHP4和UNIX, 為了使得php4可以使用共享記憶體和信號量,必須在編譯php4程式時啟動shmop和sysvsem這兩個擴充模組。

  實作方法:在PHP設定(configure)時加入下列選項。

--enable-shmop --enable-sysvsem

  這樣就使得你的PHP系統可以處理相關的IPC函數了。

  IPC是什麼?

  IPC (Inter-process communication) 是一個Unix標準通訊機制,它提供了一個讓在同一台主機不同程序之間可以互相通訊的方法。基本的IPC處理機制有3種:它們分別是共享記憶體、信號量和訊息佇列。本文中我們主要討論共享記憶體和信號量的使用。關於訊息隊列,筆者在不久的將來還會專門介紹。

  在PHP中使用共享記憶體段

  在不同的處理程序之間使用共享記憶體是實現不同進程之間相互通訊的好方法。如果你在一個行程中向所共享的記憶體寫入一段訊息,那麼所有其他的行程也可以看到這段被寫入的資料。非常方便。在PHP中有了共享記憶體的幫助,你可以實現不同進程在運行同一段PHP腳本時回傳不同的結果。或實現對PHP同時運行數量的即時查詢等等。

  共享記憶體允許兩個或多個進程共享一給定的儲存區。因為資料不需要在客戶機和伺服器之間複製,所以這是最快的一種IPC。使用共享記憶體的唯一竅門是多個進程對一給定儲存區的同步存取。

  如何建立一個共享記憶體段呢?下面的程式碼可以幫你建立共享記憶體。

$shm_id = shmop_open($key, $mode, $perm, $size);

  注意,每個共享記憶體段都有一個唯一的ID, 在PHP中,shmop_open會把建立好的共享記憶體段的ID返回,這裡我們用$shm_id記錄它。而$key是一個我們邏輯上表示共享記憶體段的Key值。不同行程只要選擇同一個Key id就可以共用同一段儲存段。習慣上我們用一個字串(類似檔案名稱一樣的東西)的雜湊值作為key id. $mode指明了共享記憶體段的使用方式。這裡由於是新建,因此值為’c’ –取create之意。如果你是存取已經建立過的共享記憶體那麼請用’a’,-- 取access之意。 $perm參數定義了存取的權限,8進制,關於權限定義請看UNIX檔案系統幫助。 $size定義了共享記憶體的大小。儘管有點象fopen(文件處理)你可不要當它同文件處理一樣。後面的描述你將會看到一點。

  例如:

$shm_id = shmop_open(0xff3, "c", 0644, 100);

  這裡我們開啟了一個共享記憶體段 鍵值0xff3 –rw-r—r—格式,大小為100位元組。

  如果需要存取已有的共享記憶體段,你必須在呼叫shmop_open中設第3、4個參數為0。

  IPC工作狀態的查詢

  在Unix下,你可以用一個命令列程式ipcs查詢系統所有的IPC資源狀態。不過有些系統要求需要超級用戶方能執行。下圖是一段ipcs的運行結果。

  上圖中系統顯示了4個共享記憶體段,注意其中第4個鍵值為0x00000ff3的就是我們剛剛運行過的PHP程式所建立的。關於ipcs的用法請參考UNIX使用手冊。

  如何釋放共享記憶體呢

  釋放共享記憶體的方法是呼叫PHP指令:shmop_delete($id)

#
shmop_delete($id);

  $id 就是你呼叫shmop_open所存的shmop_op的回傳值。還有一個方法就是用UNIX的管理指令:

  ipcrm id, id就是你用ipcs看到的ID.和你程式中的$id不一樣。不過要小心,如果你用ipcrm直接刪除共享記憶體段那麼有可能導致其他不知道這一情況的進程在引用這個已經不復存在的共享內存器時出現一些不可預測的錯誤(往往結果不妙)。

  如何使用(讀寫)共享記憶體呢

  使用如下所示函數向共享記憶體寫入資料

int shmop_write (int shmid, string data, int offset)

  其中shmid是用shmop_open傳回的句柄。 $Data變數存放了要存放的資料。 $offset描述了寫入從共享記憶體的開始第一個位元組的位置(以0開始)。

  讀取操作是:

#
string shmop_read (int shmid, int start, int count)

  同样,指明$shmid,开始偏移量(以0开始)、总读取数量。返回结果串。这样,你就可以把共享内存段当作是一个字节数组。读几个再写几个,想干嘛就干嘛,十分方便。

  多进程问题的考虑

  现在,在单独的一个PHP进程中读写、创建、删除共享内存方面上你应该没有问题了。但是,显然实际运行中不可能只是一个PHP进程在运行中。如果在多个进程的情况下你还是沿用单个进程的处理方法,你一定会碰到问题 ---- 著名的并行和互斥问题。比如说有2个进程同时需要对同一段内存进行读写。当两个进程同时执行写入操作时,你将得到一个错误的数据,因为该段内存将之可能是最后执行的进程的内容,甚至是由2个进程写入的数据轮流随机出现的一段混合的四不象。这显然是不能接受的。为了解决这个问题,我们必须引入互斥机制。互斥机制在很多操作系统的教材上都有专门讲述,这里不多重复。实现互斥机制的最简单办法就是使用信号灯。信号量是另外一种进程间通讯(IPC)的方式,它同其他IPC机构(管道、FIFO、消息队列)不同。它是一个记数器,用于控制多进程对共享数据的存储。同样的是你可以用ipcs和ipcrm实现对信号灯使用状态的查询和对其实现删除操作。在PHP中你可以用下列函数创建一个新的信号量并返回操作该信号量的句柄。如果该key指向的信号量已经存在,sem_get直接返回操作该信号量的句柄。

int sem_get (int key [, int max_acquire [, int perm]])

  $max_acquire 指明同时最多可以用几个进程进入该信号而不必等待该信号被释放(也就是最大同时处理某一资源的进程数目,一般该值均为一)。$perm指明了访问权限。

  一旦你成功的拥有了一个信号量,你对它所能做的只有2种:请求、释放。当你执行释放操作时, 系统将把该信号值减一。如果小于0那就还设为0。而当你执行请求操作时,系统将把该信号值加一,如果该值大于设定的最大值那么系统将挂起你的处理进程直到其他进程释放到小于最大值为止。一般情况下最大值设为1,这样一来当一个进程获得请求时其他后面的进程只能等待它退出互斥区后释放信号量才能进入该互斥区并同时设为独占方式。这样的信号量常称为双态信号量。当然,如果初值是任意一个正数就表明有多少个共享资源单位可供共享应用。

  申请、释放操作的PHP格式如下:

int sem_acquire (int sem_identifier) 申请 
int sem_release (int sem_identifier) 释放 
其中sem_identifier是调用sem_get的返回值(句柄)。  
一个简单的互斥协议例子 
下面是一段很简单的互斥操作规程。 
$semid=sem_get(0xee3,1,0666); 
$shm_id = shmop_open(0xff3, "c", 0644, 100); 
sem_acquire($semid);      //申请 
/* 进入临界区*/ 
这里,对共享内存进行处理 
sem_release($semid);      //释放

  正如你所看到的,互斥的实现很简单:申请进入临界区,对临界区资源进行操作(比如修改共享内存)退出临界区并释放信号。这样一来就可以保证在同一个时间片中不可能有同时2个进程对同一段共享内存进行操作。因为信号量机制保证一个时间片只能由一个进程进入,其他进程必须等待当前处理的进程完成后方能进入。

  临界区一般是指那些不允许同时有多个进程并发处理的代码段。

  要注意的是:在PHP中必须由同一个进程释放它所占用的信号量。在一般系统中允许进程释放别的进程占用的信号。在编写临界区代码一定要小心设计资源的分配,避免A等B,B等A的死锁情况发生。

  运 用

  IPC的运用是十分广泛的。比如,在不同进程间保存一个解释过的复杂的配置文件、或具体设置的用户等,以避免重复处理。我也曾经用共享内存的技术把一大批PHP脚本必须引用的一个很大的文件放入共享内存,并由此显著提升了Web服务的速度、消除了部分瓶颈。关于它的使用还有聊天室,多路广播等等。IPC的威力取决于你的想象力的大小。如果本文对你有一点点启发,那我不胜荣幸。愿意很你讨论这令人入迷的电脑技术。

<?php
//print_r($res_area);
//$res_area = array("username" => "yanjing5462","password" => "132");
$new_area = serialize($res_area);
//申请共享内存空间
$shm_id = @shmop_open(0xff9, "a", 0, 0);
if(empty($shm_id))
{
echo "创建";
$shm_id = shmop_open(0xff9, "c", 0700, 1048576); //10MB
//$value = "我国已成为全球能源建设规模最大的市场";
//写入共享内存空间
echo $shm_id;
shmop_write($shm_id, $new_area, 0);
  }
else
{
echo &#39;不创建&#39;.time();
shmop_delete($shm_id);
shmop_close($shm_id);
}
$shmid = shmop_open(0xff9, "a", 0, 0);
  $my_string = shmop_read($shmid, 0, 1048576);
  print_r( unserialize($my_string) );
?>

 以上就是php共享内存使用的代码详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!



陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn