網頁

2008年1月31日 星期四

利用PHP用寫Multi Process程式 - 2 使用信號機

利用PHP用寫Multi Process程式 - 2 使用信號機

2.1 互斥機制

多程序程式設計一定會遇到的問題就是:不同的程序間在兢爭相同的資源。
資源可能是螢幕的輸出或是資料庫的連線。我們不希望兩個以上的程序兢爭螢幕輸出資源,到時可能演變成一個程序輸出兩行而另一個程序再輸出兩行,這樣的輸出是不能看的。
為了解決這個問題,我們必須引入互斥機制,就要有關鍵區域(Critical Area)和信號機(Semaphore)的技術。
在 PHP 下,可以參考官方文件 Semaphore, Shared Memory and IPC Functions
要是以上幾個名詞都忘了的話,再溫習一下作業系統的書吧。


2.2 信號機的使用方式

2.2.1 建立信號機

使用sem_get()可以取得一個新的信號機。

格式

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

參數

  • key : 信號機的編號,要是一個還沒有用過的編號。通常使用 ftok() 用來取得
  • max_acquire : 設定一個信號機可以讓多少程序取用,預設為1
  • perm : 設定訪問權限

2.2 信號機的使用

2.2.1 建立信號機

使用sem_get()可以取得一個新的信號機。

格式

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

參數

  • key : 信號機的編號,要是一個還沒有用過的編號。通常使用 ftok() 用來取得
  • max_acquire : 設定一個信號機可以讓多少程序取用,預設為1
  • perm : 設定訪問權限

2.2.2 申請

使用 sem_acquire() 向信號機申請減少一個資源數,並且進入臨界區。

格式

int sem_acquire (int sem_identifier)

參數

  • sem_identifier:信號機的編號

2.2.3 釋放信號機

使用 sem_acquire() 通知信號機釋放一個資源數,並且離開臨界區。

格式

int sem_release (int sem_identifier)

參數

  • sem_identifier:信號機的編號

2_3 簡單的範例

<?php
$semid=sem_get( 0xFF3, 1, 0666);
sem_acquire($semid);//向編號為$semid信號機申請進入臨界區
/* 臨界區開始 */
  /*這在裡對共用資源作操作 */
/* 臨界區結束 */
sem_release($semid);//釋放編號為$semid的信號機
?>

2.4 信號機的程式範例

2.4.1 範例

<?php
// 寫兩個子行程搶資源,用semapher做保護
$process_num = 3;
print "老爸:我是老爸,我要生{$process_num}個小孩。\n";
$children = array();
$source_id = ftok('semaghor.php', 'w');
$sem = sem_get($source_id, 1); //取得一個semaphore,可以申請的只有一個

/* 以下要來生小孩 */
$i = 1;
while($i <= $process_num) { 
$pid = pcntl_fork(); //生出一個子程序 
if($pid == -1) { //要是 $pid 是 -1 那就是出錯了  
exit(1); //離開,並且報告出錯 
} else if ($pid != 0) {  //若$pid不是0的話,那就是父行程  
/*這是老爸專區*/  
print "老爸:生了一個第{$i}個孩子,pid是{$pid}\n";  
$children[] = $pid; 
} else { //子程序拿到的 $pid 是 0  
/*這是小朋友區*/  
break; //直接出迴圈 
} 
$i++;
}
if($pid) {  
/* 老爸會進到這裡 */ 
$status = null; 
print "老爸:老爸會等大家玩好才離開\n"; 
foreach($children as $pid) {
//要等每個孩子都離開才離開  
pcntl_waitpid($pid, $status);   
print "老爸:pid是{$pid}的那個孩子,回去時他告訴我他的狀況是{$status}\n"; 
} 
print '老爸也要走了'."\n";
} else { 
/*以下是小朋友遊樂區*/ 
for($j=1;$j<3;$j++)>

2.4.2 執行結果

老爸:我是老爸,我要生3個小孩。
老爸:生了一個第1個孩子,pid是11480
我是第1個小朋友,我是第1次進入了臨界區,我要玩1秒
老爸:生了一個第2個孩子,pid是11481
老爸:生了一個第3個孩子,pid是11482
老爸:老爸會等大家玩好才離開
我是第1個小朋友,要離開臨界區了
我是第2個小朋友,我是第1次進入了臨界區,我要玩2秒
我是第2個小朋友,要離開臨界區了
我是第3個小朋友,我是第1次進入了臨界區,我要玩3秒
我是第3個小朋友,要離開臨界區了
我是第1個小朋友,我是第2次進入了臨界區,我要玩1秒
我是第1個小朋友,要離開臨界區了
我是第2個小朋友,我是第2次進入了臨界區,我要玩2秒
我是第1個小朋友,要走了
老爸:pid是11480的那個孩子,回去時他告訴我他的狀況是0
我是第2個小朋友,要離開臨界區了
我是第3個小朋友,我是第2次進入了臨界區,我要玩3秒
我是第2個小朋友,要走了
老爸:pid是11481的那個孩子,回去時他告訴我他的狀況是0
我是第3個小朋友,要離開臨界區了
我是第3個小朋友,要走了
老爸:pid是11482的那個孩子,回去時他告訴我他的狀況是0
老爸也要走了

沒有留言: