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);

?>

完美的处理了进程之间抢资源的问题,实现了操作的原子性!

猜你喜欢

转载自blog.csdn.net/rorntuck7/article/details/84582191