1. 程式人生 > >php程序間通訊--訊號量

php程序間通訊--訊號量

 訊號量是什麼? 訊號量 : 又稱為訊號燈、旗語 用來解決程序(執行緒同步的問題),類似於一把鎖,訪問前獲取鎖(獲取不到則等待),訪問後釋放鎖。

  舉一個生活中的例子:以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛直接進入,然後放下車攔,剩下的車則必須在入口等待,此後來的車也都不得不在入口

處等待。這時,有一輛車離開停車場,看門人得知後,開啟車攔,放入外面的一輛進去,如果又離開兩輛,則又可以放入兩輛,如此往復。在這個停車場系統中,車位是公共資源,每輛車好比一個執行緒,看門人起的就是訊號量的作用

  下面我們來看一下訊號量的幾個函式:

<?php
$key=ftok(__FILE__,'t');

/**
 * 獲取一個訊號量資源
 int $key [, int $max_acquire = 1 [, int $perm = 0666 [, int $auto_release = 1 ]]] 
 $max_acquire:最多可以多少個程序同時獲取訊號
 $perm:許可權 預設 0666
 $auto_release:是否自動釋放訊號量
 */
$sem_id=sem_get($key);

#獲取訊號
sem_acquire($seg_id);

//do something 這裡是一個原子性操作

//釋放訊號量
sem_release($seg_id);

//把次訊號從系統中移除
sem_remove($sem_id);


//可能出現的問題
$fp = sem_get(fileinode(__DIR__), 100);
sem_acquire($fp);

$fp2 = sem_get(fileinode(__DIR__), 1);
sem_acquire($fp2);
?>
<?php
//共享記憶體通訊

//1、建立共享記憶體區域
$shm_key = ftok(__FILE__, 't');
$shm_id = shm_attach( $shm_key, 1024, 0655 );
const SHARE_KEY = 1;
$childList = [];


//加入訊號量
$sem_id = ftok(__FILE__,'s');
$signal = sem_get( $sem_id );

//2、開3個程序 讀寫 該記憶體區域
for ( $i = 0; $i < 3; $i++ ) {

     $pid = pcntl_fork();
	 
	 if ( $pid == -1 ) {
        exit('fork fail!' . PHP_EOL);
     } else if ( $pid == 0 ) {
		  // 獲得訊號量
        sem_acquire($signal);
		
		//子程序從共享記憶體塊中讀取 寫入值 +1 寫回
		 if ( shm_has_var($shm_id, SHARE_KEY) ) {
			 // 有值,加一
            $count = shm_get_var($shm_id, SHARE_KEY);
            $count ++;
            //模擬業務處理邏輯延遲
            $sec = rand( 1, 3 );
            sleep($sec);

            shm_put_var($shm_id, SHARE_KEY, $count); 
		 } else {
            // 無值,初始化
            $count = 0;
            //模擬業務處理邏輯延遲
            $sec = rand( 1, 3 );
            sleep($sec);

            shm_put_var($shm_id, SHARE_KEY, $count);
        }

        echo "child process " . getmypid() . " is writing ! now count is $count\n";
		// 用完釋放
        sem_release($signal);
        exit( "child process " . getmypid() . " end!\n" );
	 } else {
		  $childList[$pid] = 1;
	 }
	
}
 
// 等待所有子程序結束
while( !empty( $childList ) ){
    $childPid = pcntl_wait( $status );
    if ( $childPid > 0 ){
        unset( $childList[$childPid] );
    }
}


//父程序讀取共享記憶體中的值
$count = shm_get_var($shm_id, SHARE_KEY);
echo "final count is " . $count . PHP_EOL;
 

//3、去除記憶體共享區域
#從系統中移除
shm_remove($shm_id);
#關閉和共享記憶體的連線
shm_detach($shm_id);

?>

完美的處理了程序之間搶資源的問題,實現了操作的原子性!