この記事では、PHP4 環境でプロセス間通信メカニズムである IPC (Inter-Process-Communication) を使用する方法について説明します。この記事で説明するソフトウェア環境は linux+php4.0.4 以降です。まず、PHP4 と UNIX がインストールされていることを前提としています。php4 で共有メモリとセマフォを使用するには、php4 プログラムのコンパイル時に 2 つの拡張モジュール shmop と sysvsem をアクティブにする必要があります。
実装方法:PHPのセットアップ(configure)時に以下のオプションを追加します。
--enable-shmop --enable-sysvsem
これにより、PHP システムが関連する IPC 関数を処理できるようになります。
IPCとは何ですか?
IPC (プロセス間通信) は Unix 標準の通信メカニズムであり、同じホスト上の異なるプロセスが相互に通信する方法を提供します。 IPC には、共有メモリ、セマフォ、メッセージ キューという 3 つの基本的な処理メカニズムがあります。この記事では、主に共有メモリとセマフォの使用について説明します。メッセージキューについては、近いうちに具体的に紹介する予定です。
PHP で共有メモリセグメントを使用する
異なる処理プロセス間で共有メモリを使用することは、異なるプロセス間の相互通信を実現する良い方法です。 1 つのプロセスで共有メモリに情報を書き込むと、他のすべてのプロセスも書き込まれたデータを参照できます。とても便利。 PHP の共有メモリを利用すると、異なるプロセスが同じ PHP スクリプトを実行したときに異なる結果を得ることができます。または、同時に実行されている PHP の数に対するリアルタイム クエリを実装するなど。
共有メモリを使用すると、2 つ以上のプロセスが特定のストレージ領域を共有できます。クライアントとサーバーの間でデータをコピーする必要がないため、これは最も高速なタイプの IPC です。共有メモリを使用する唯一のコツは、複数のプロセスが特定のメモリ領域に同時にアクセスすることです。
共有メモリセグメントを作成するにはどうすればよいですか?次のコードは、共有メモリの作成に役立ちます。
$shm_id = shmop_open($key, $mode, $perm, $size);
各共有メモリ セグメントには一意の ID があることに注意してください。PHP では、shmop_open は作成された共有メモリ セグメントの ID を返します。これを記録するために $shm_id を使用します。 $key は、共有メモリ セグメントを論理的に表す Key 値です。異なるプロセスは、同じキー ID を選択する限り、同じストレージ セグメントを共有できます。 $mode は共有メモリ セグメントの使用方法を指定するため、文字列 (ファイル名など) のハッシュ値を使用するのが一般的です。これは新規作成であるため、値は「c」、つまり作成を意味します。作成した共有メモリにアクセスする場合は、アクセスを意味する「a」を使用してください。 $perm パラメータは、アクセス許可を 8 進数形式で定義します。許可の定義については、UNIX ファイル システムのヘルプを参照してください。 $size は共有メモリのサイズを定義します。 fopen (ファイル処理) に少し似ていますが、ファイル処理と同じと考えるべきではありません。これについては後の説明で少し説明します。
例:
$shm_id = shmop_open(0xff3, "c", 0644, 100);
ここでは、キー値 0xff3 –rw-r—r—format とサイズ 100 バイトの共有メモリ セグメントを開きます。
既存の共有メモリセグメントにアクセスする必要がある場合は、shmop_openを呼び出すときに3番目と4番目のパラメータを0に設定する必要があります。
IPC 動作ステータスのクエリ
Unix では、コマンド ライン プログラム ipcs を使用して、システム内のすべての IPC リソースのステータスをクエリできます。ただし、一部のシステム要件ではスーパーユーザーが実行する必要があります。下の図は、ipcs の実行結果の一部です。
上の図では、システムは 4 つの共有メモリ セグメントを表示しています。4 番目のキー値は、先ほど実行した PHP プログラムによって作成された 0x00000ff3 であることに注意してください。 ipcs の使用方法については、UNIX ユーザー マニュアルを参照してください。
共有メモリを解放する方法
共有メモリを解放する方法は、PHPコマンドshmop_delete($id)を呼び出すことです
shmop_delete($id);
$idは、shmop_openを呼び出して保存したshmop_opの戻り値です。もう 1 つの方法は、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 '不创建'.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)!